library(dplyr)
Attaching package: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
library(ggplot2)
library(forcats)
library(here)
here() starts at /Users/avrilwang/Desktop/Project-Plasmodium
library(deSolve)
library(crone)
library(optimParallel)
Loading required package: parallel
library(doParallel)
Loading required package: foreach
Loading required package: iterators
library(doRNG)
Loading required package: rngtools
library(arrow)
Attaching package: ‘arrow’
The following object is masked from ‘package:utils’:
timestamp
library(stringr)
library(parallel)
library(ggpubr)
Notebook for plotting all of the figures for PloS Biology manuscript submission
Guidelines: taken from https://journals.plos.org/plosbiology/s/figures#loc-figure-file-requirements 1. format: tiff 2. max file size: 10 MB 3. text size: Arial, Times, or Symbol font only in 8-12 point 2. figure size: Width: 789 – 2250 pixels (at 300 dpi). Height maximum: 2625 pixels (at 300 dpi).
overall manuscript setup
- Fig 1: model schematic
- Fig 2. best single and co-infection infection cue [monocue] ——-> supplmentary table of parameters and fitness
- Fig 3. dual cue optimization [monocue] ——-> supplementary table of flexible optimization
- Fig 4. heterocue competition [heterocue]
- Fig 5. partitioning single cue success and consequences of bottom+top down regulation [monocue]
- Fig 6. consequences of adopting best cue [monocue]
#———————————–# best single and co-infection cue #———————————–# Figure displaying the reaction norms of best single and co-infection.
#——- optimal cue reaction norm ———–# # read data
# single infection dynamics, reaction norms, and rugs
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet"))
si_rn.df <- read_parquet(here("data/si_dyn/si_rn.parquet"))
si_rug.df <- read_parquet(here("data/si_dyn/si_rug.parquet"))
# co-infection dynamics, reaction norms, and rugs
ci_dyn.df <- read_parquet(here("data/ci_dyn/ci_dyn.parquet"))
ci_rn.df <- read_parquet(here("data/ci_dyn/ci_rn.parquet"))
ci_rug.df <- read_parquet(here("data/ci_dyn/ci_rug.parquet"))
process data for reaction norm
# import labelling scheme
ez_label <- read.csv(here("data/ez_label.csv"))
# get si_label with ci cue range
si_ci_rug.df <- ci_rug.df %>%
mutate(label_si = case_when(
label %in% c("I", "I1+I2") ~ "I",
label %in% c("I log","I1+I2 log") ~ "I log",
label %in% c("Ig", "Ig1+Ig2") ~ "Ig",
label %in% c("Ig log") ~ "Ig log",
label %in% c("sum", "I+Ig") ~ "I+Ig",
label %in% c("sum log", "I+Ig log") ~ "I+Ig log",
label == "R" ~ "R",
label == "R log" ~ "R log",
label %in% c("G", "G1+G2") ~ "G",
label == "G log" ~ "G log"
))
# get limit for si_rug
si_rug_lim.df <- si_rug.df %>%
filter(time <= 20) %>%
group_by(label)%>%
summarise(min = min(value, na.rm = T)*0.9,
max = max(value, na.rm = T)*1.1) %>%
select(label_si = label, min_si = min, max_si = max)
# filter to restriction conversion rate reaction norm range to cue ranges that appear in rug
## change to Inf/-inf to NA. Note that I am first joining with si rug lim to check which limit is larger, We will go with the cue range that has the largest span
ci_rug_lim.df <- si_ci_rug.df %>%
group_by(label) %>%
mutate(min = min(value, na.rm = T)*0.9,
max = max(value, na.rm = T)*1.1) %>%
distinct(label, .keep_all = T) %>%
select(label, label_si, min, max)
rug_lim.final <- ci_rug_lim.df %>% left_join(si_rug_lim.df, by = "label_si") %>%
mutate(final_min = min(min, min_si),
final_max = max(max, max_si))
# get second rug_lim.final for single infection
rug_lim.final2 <- rug_lim.final %>%
group_by(label_si) %>%
mutate(final_min = min(final_min, na.rm = T),
final_max = max(final_max, na.rm = T))
# filter ci_rn by limit
ci_rn.df2 <- ci_rn.df %>%
left_join(rug_lim.final, by = "label") %>%
group_by(label) %>%
filter(cue_range <= final_max & cue_range >= final_min)
match single infection rn with coinfection
# get ci label to si rug and filter by limit
si_rn.df2 <- left_join(si_rn.df, select(ez_label, label_si, label_ci), by = c("label" = "label_si")) %>%
left_join(rug_lim.final, by = c("label_ci" = "label")) %>%
group_by(label_ci) %>%
filter(cue_range <= final_max & cue_range >= final_min) %>%
select(cue_range, cr, label_ci, label_si)
# get ci label to si rug
si_rug.df2 <- select(si_rug.df, value, label_si = label)
plot reaction norm
# join with ezlabel
ci_rn.df3 <- ci_rn.df2 %>% left_join(ez_label, by = c("label" = "label_ci"))
si_rn.df3 <- si_rn.df2 %>% left_join(ez_label, by = "label_ci")
ci_rug.df3 <- ci_rug.df %>% left_join(ez_label, by = c("label" = "label_ci"))
si_rug.df3 <- si_rug.df2 %>% left_join(ez_label, by = "label_si")
# redo order of cues
ci_rn.df3$label <- factor(ci_rn.df3$label,
levels = c("I", "I log",
"I1+I2", "I1+I2 log",
"Ig", "Ig log",
"I+Ig", "I+Ig log",
"sum", "sum log",
"G", "G log",
"G1+G2", "Ig1+Ig2",
"R", "R log"))
si_rn.df3$label_ci <- factor(si_rn.df3$label_ci,
levels = c("I", "I log",
"I1+I2", "I1+I2 log",
"Ig", "Ig log",
"I+Ig", "I+Ig log",
"sum", "sum log",
"G", "G log",
"G1+G2", "Ig1+Ig2",
"R", "R log"))
ci_rug.df3$label <- factor(ci_rug.df3$label,
levels = c("I", "I log",
"I1+I2", "I1+I2 log",
"Ig", "Ig log",
"I+Ig", "I+Ig log",
"sum", "sum log",
"G", "G log",
"G1+G2", "Ig1+Ig2",
"R", "R log"))
si_rug.df3$label_ci <- factor(si_rug.df3$label_ci,
levels = c("I", "I log",
"I1+I2", "I1+I2 log",
"Ig", "Ig log",
"I+Ig", "I+Ig log",
"sum", "sum log",
"G", "G log",
"G1+G2", "Ig1+Ig2",
"R", "R log"))
# plot
opt_cue_pl.A <- ggplot() +
geom_line(data = ci_rn.df3, aes(x = cue_range, y = cr, color = "Co-infection")) +
geom_line(data = si_rn.df3, aes(x = cue_range, y = cr, color = "Single infection"), linetype = "dashed") +
geom_rug(data = ci_rug.df3, aes(x = value), color = "#4575b4", sides = "t") +
geom_rug(data = si_rug.df3, aes(x = value), color = "#fc8d59", sides = "b") +
facet_wrap(~ez_label, scales = "free_x", ncol = 2) +
theme_bw() +
labs(y = "Conversion rate", x = "Cue range", color = "Infection") +
scale_x_continuous(labels = function(x) format(x, scientific = T),
guide = guide_axis(check.overlap = TRUE)) +
theme(axis.text.x = element_text(size = 7)) +
scale_color_manual(values=c( "#4575b4", "#fc8d59"))
ggsave(here("figures/plos-bio/reaction_norm.png"), width = 7, height = 10)
#———- plot best fitness ————–# # import in data
# single infection dynamics
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet"))
# co-infection dynamics
ci_dyn.df <- read_parquet(here("data/ci_dyn/ci_dyn.parquet"))
ez_label <- read.csv(here("data/ez_label.csv"))
process for final 20 days fitness
# get single infection maximum tau_cum for 20 days
si_fitness.df <- si_dyn.df %>%
filter(variable == "tau_cum" & time == 20)
# get single infection maximum tau_cum for 20 days
si_fitness.df <- si_dyn.df %>%
filter(variable == "tau_cum" & time == 20)
# get co-infection maximum tau_cum for 20 days
ci_fitness.df <- ci_dyn.df %>%
filter(variable == "tau_cum1" & time == 20)
Error in filter(., variable == "tau_cum1" & time == 20) :
object 'ci_dyn.df' not found
plot
opt_cue_pl.B <- ggplot() +
geom_point(data = si_ci_fitness.df, aes(x = fitness_si, y = fitness_ci, color = ez_label_si, shape = ez_label_si), size = 2.5) +
ggrepel::geom_label_repel(data = si_ci_fitness.df, aes(label = ez_label, x = fitness_si, y = fitness_ci),
fill = "white",xlim = c(-Inf, Inf), ylim = c(NA, NA)) +
labs(x = "Optimal single-infection fitness", y = "Optimal Co-infection fitness (per strain)",
color = "Single infection cue", shape = "Single infection cue") +
scale_shape_manual(values = 15:24) +
lims(x = c(8, 10.5)) +
geom_vline(xintercept = 9.2, linetype = "dashed", alpha = 0.5) + # si good cue cutoff
geom_hline(yintercept = 2.25, linetype = "dashed", alpha = 0.5) + # ci good cue cutoff
theme_bw() +
coord_cartesian(clip = "off") +
theme(plot.margin=margin(r=0))
#————– timeseries conversion rate —————–# # process info for single infection
plot single infection conversion rate heatmap
# plot poor performing
si_cr.pl1 <- ggplot() +
geom_tile(data = si_cr.poor, aes(x = time, y = forcats::fct_reorder(ez_label_si, fitness_si), fill = value)) +
labs(x = "Time (days)", y = "Low performing\nsingle infection cues", fill = "Conversion rate") +
scale_fill_viridis_c(limits = c(0, 1)) +
xlim(1, 20) +
theme_bw()
# plot high perfomring
si_cr.pl2 <- ggplot() +
geom_tile(data = si_cr.high, aes(x = time, y = forcats::fct_reorder(ez_label_si, fitness_si), fill = value)) +
labs(x = "", y = "High performing\nsingle infection cues", fill = "Conversion rate") +
scale_fill_viridis_c(limits = c(0, 1)) +
xlim(1, 20) +
theme_bw()
save figure for poster
ggarrange(si_cr.pl2, si_cr.pl1, common.legend = T, ncol = 1, nrow = 2)
Warning: Removed 6000 rows containing missing values (geom_tile).
Warning: Removed 6000 rows containing missing values (geom_tile).
Warning: Removed 10000 rows containing missing values (geom_tile).


co-infection conversion rate heatmap
plot co-infeciton convesion rate heatmap
plot
# plot poor performing
ci_cr.pl1 <- ggplot() +
geom_tile(data = ci_cr.poor, aes(x = time, y = forcats::fct_reorder(ez_label_si, fitness_ci), fill = value)) +
labs(x = "Time (days)", y = "Low performing\nco-infection cues", fill = "Conversion rate") +
scale_fill_viridis_c(limits = c(0, 1)) +
xlim(1, 20) +
theme_bw()
# plot high perfomring
ci_cr.pl2 <- ggplot() +
geom_tile(data = ci_cr.high, aes(x = time, y = forcats::fct_reorder(ez_label_si, fitness_ci), fill = value)) +
labs(x = "", y = "High performing\nco-infection cues", fill = "Conversion rate") +
scale_fill_viridis_c(limits = c(0, 1)) +
xlim(1, 20) +
theme_bw()
#——— assemble final figure ————–#
tiff(here("figures/plos-bio/opt_cue.tiff"), units="px", width = 2250, height = 1500, res=300, compression = "lzw", type="quartz")
ggarrange(opt_cue_pl.A, opt_cue_pl.BC, ncol = 2, nrow = 1, labels = c("A", ""), widths = c(0.75, 1))
Warning: ggrepel: 7 unlabeled data points (too many overlaps). Consider increasing max.overlaps
dev.off()
null device
1
#——————————————–# # dual cue optimization figure #——————————————–#
source(here("functions/chabaudi_si_clean_high.R"))
source(here("functions/chabaudi_si_clean.R"))
source(here("functions/par_to_hm_te.R"))
#———- plotting fitness of dual vs single cue opt ———# # import in previous data
# dual cue fitness
dual_fitness.df <- read.csv(here("data/dual_cue_opt4/dual_cue_fitness_20.csv"))
## make label and filter out very low fitness
dual_fitness.df <- dual_fitness.df %>%
mutate(temp_label = gsub("log", "log10", label),
temp_label_b = gsub("log", "log10", label_b),
label_final = paste0(temp_label, "+", temp_label_b)) %>%
filter(value > 2)
# get single cue fitness
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet"))
si_fitness.df <- si_dyn.df %>%
filter(variable == "tau_cum" & time == 20)
# join si and dual cue
dual_si_fitness.df <- dual_fitness.df %>%
left_join(select(si_fitness.df, id, si_fitness = value), by = "id") %>%
left_join(select(si_fitness.df, id_b = id, si_fitness_b = value), by = "id_b") %>%
mutate(si_fitness_max = ifelse(si_fitness > si_fitness_b, si_fitness, si_fitness_b),
dual_label = gsub("log", "log10", paste(label, "+", label_b)))
plot

#———– time series conversion rate ————-# # dynamics simulation of high parameter cues (these serve as reference points)
# best dual cue combo
dual.cr <- chabaudi_si_clean(
parameters_cr = c(4.446192033, 10.97518275, 1.38762817, 23.3059254, -3.452052371, -18.0070692, 39.66614226, -3.545193141, 18.78350799),
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 20, by = 1e-3),
cue_range = seq(6, 7, by = 1/500),
cue_range_b = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/500),
cue = "R",
cue_b = "I",
log_cue = "log10",
log_cue_b = "log10",
solver = "vode",
dyn = T
)
# when time is used as a cue (high parameter)
time.cr <- chabaudi_si_clean_high(
parameters_cr = c(9.154314, -7.570829, -22.506638 , 3.382405 ,-13.453519 ,-17.011485 , 3.678181, -12.851895 ,-26.115158),
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 20, by = 1e-3),
cue_range = seq(0, 20, by = 1e-3),
cue = "t",
solver = "vode",
dyn = T)
# when asexual iRBC is used as a cue (high flexibility)
I_high.cr <- chabaudi_si_clean_high(
parameters_cr = c(1.296675, 3.544034 , 4.907484, 2.174249, -3.238309 ,-5.181614 ,-1.645072 , 1.834302 , 1.581011),
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 20, by = 1e-3),
cue_range = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/5000),
cue = "I",
log_cue = "log10",
solver = "vode",
dyn = T)
# when asexual iRBC is used as a cue (normal flexibility)
I.cr <- chabaudi_si_clean(
parameters_cr = c(5.463558, 2.383948, -17.757281, 4.571835),
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 20, by = 1e-3),
cue_range = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/5000),
cue = "I",
log_cue = "log10",
solver = "vode",
dyn = T)
# process
I_high.cr2 <- I_high.cr %>% filter(variable == "cr") %>% mutate(label_new = "I log10 flexible") %>% select(-variable)
I.cr2 <- I.cr %>% filter(variable == "cr") %>% mutate(label_new = "I log10") %>% select(-variable)
time_high.cr2 <- time.cr %>% filter(variable == "cr") %>% mutate(label_new = "Time flexible") %>% select(-variable)
dual.cr2 <- dual.cr %>% filter(variable == "cr") %>% mutate(label_new = "R log10 + I log10") %>% select(-variable)
# combine
dual_cr.df <- rbind(I_high.cr2, I.cr2, time_high.cr2, dual.cr2)
plot
ggplot() +
geom_line(data = dual_cr.df, aes(color = label_new, x = time, y = value), size = 1) +
geom_point(data = dual_cr.df %>% filter(time%%1 == 0), aes(color = label_new, x = time, y = value, shape = label_new), size = 2) +
labs(x = "Time (days)", y = "Conversion rate", color = "Cue", shape = "Cue") +
xlim(0, 20) +
scale_color_manual(values = c("#4575b4", "#91bfdb","#fc8d59","#fdcb44")) +
theme_bw() +
theme(legend.position="bottom") +
guides(color = guide_legend(nrow = 2, byrow = TRUE))
Warning: Removed 3 row(s) containing missing values (geom_path).
Warning: Removed 3 rows containing missing values (geom_point).

#———— reaction norm heatmap of R log10 + I log10 ————# # process data
# make heatmap df
R_I.hm <- par_to_hm_te(par = c(4.446192033, 10.97518275, 1.38762817, 23.3059254, -3.452052371, -18.0070692, 39.66614226, -3.545193141, 18.78350799),
cue_range = seq(6, 7, length.out = 500),
cue_range_b = seq(0, 6.77815125, length.out = 500))
Error in par_to_hm_te(par = c(4.446192033, 10.97518275, 1.38762817, 23.3059254, :
could not find function "par_to_hm_te"
plot
ggplot() +
geom_raster(data = R_I.hm, aes(x = cue_range_b, y = cue_range, fill = cr)) +
scale_fill_viridis_c() +
geom_path(data = R_I.dyn, aes(x = log_I, y = log_R), color = "white", arrow = arrow(angle = 30, length = unit(0.1, "inches"))) +
geom_point(data = R_I.dyn %>% filter(row_number() %% 1000 == 1 & time <= 20), aes(x = log_I, y = log_R), color = "white") +
xlim(0.99*min(hablar::s(R_I.dyn$log_I), na.rm = T), 1.01* max(hablar::s(R_I.dyn$log_I), na.rm = T)) +
ylim(0.99*min(hablar::s(R_I.dyn$log_R), na.rm = T),1.01* max(hablar::s(R_I.dyn$log_R), na.rm = T)) +
labs(y = "RBC log10", x = "Asexual iRBC log10", fill = "Conversion rate") +
theme_dark()
Warning: Removed 219202 rows containing missing values (geom_raster).

save figure for poster
ggarrange(dual_cr.pl2, dual_rn.pl2, align = "h", widths = c(1.25, 1))
Warning: Removed 3 row(s) containing missing values (geom_path).
Warning: Removed 3 rows containing missing values (geom_point).
Warning: Removed 219202 rows containing missing values (geom_raster).

#——– assemble final figure ————-#
# assemble panel A
dual.pl <- ggarrange(dual_si_fitness.pl, dual_pl.BC, ncol = 2, labels = c("A", ""), width = c(1, 0.75))
Warning in as_grob.default(plot) :
Cannot convert object of class numeric into a grob.
#——————————————-# # heterocue adoption #——————————————-#
#——- static competition —————# # calculate fitness difference for 20 days
import and process data
min(static.df4$fitness_difference)
[1] -0.922165
plot
static.pl <- ggarrange(static.pl1, static.pl2, align = "hv", widths = c(1, 0.2))
Warning: Graphs cannot be vertically aligned unless the axis parameter is set. Placing graphs unaligned.
ggsave(here("figures/plos-bio/static_heatmap.tiff"), width = 10, height = 6)
#—— invasion matrix ——————–# # import in data (already 20 days )
invade.df <- read.csv(here("data/ci_invasion.csv"))
process data for invasion matrix
invade.mat4 <- rbind(invade.mat3,
invade.mat3 %>%
rename(V2_label = V1_label, V1_label = V2_label) %>%
select(V1_label, V2_label, invasion)) %>%
mutate(across(ends_with("label"),
~factor(.x, levels = levels))) %>%
filter(as.integer(V1_label) < as.integer(V2_label)) %>%
mutate(V2_label = forcats::fct_rev(V2_label))
Adding missing grouping variables: `id_alt`
plot invasion matrix

create summary bar chart
# create a stacked barchart for summary
## filter out na
invade.matalt <- invade.mat3 %>% na.exclude()
# get frquency from both sides. Note when grouping for V2, from the perspective of cue 2, scenarrio when strain 2 invade = strain 1 invade
invade.matalt1 <- invade.matalt %>% group_by(V1_label, invasion) %>%
summarize(frequency_1 = n())
invade.matalt2 <- invade.matalt %>%
mutate(invasion_alt = case_when(
invasion == "Only strain 1 invasion" ~ "Only strain 2 invasion",
invasion == "Only strain 2 invasion" ~ "Only strain 1 invasion",
invasion == "Mutual invasion" ~ "Mutual invasion",
invasion == "Mutual non-invasion" ~ "Mutual non-invasion"
)) %>%
group_by(V2_label, invasion_alt) %>%
summarize(frequency_2 = n())
# full join and sum. has confirmed all of them add up to 14
invade.matalt3 <- full_join(invade.matalt1, invade.matalt2, by = c("V1_label" = "V2_label", "invasion" = "invasion_alt"))
invade.matalt3[is.na(invade.matalt3)] <- 0
invade.matalt4 <- invade.matalt3 %>%
mutate(freq = frequency_1 + frequency_2) %>%
mutate(temp = case_when(
invasion == "Only strain 1 invasion" ~ freq
)) %>%
group_by(V1_label) %>%
mutate(invade_1_freq = max(temp, na.rm = T))
invasion.pl2 <- ggplot() +
geom_bar(data = invade.matalt4, aes(x = freq, y = reorder(V1_label, invade_1_freq), fill = forcats::fct_rev(factor(invasion, levels = c("Only strain 1 invasion", "Only strain 2 invasion", "Mutual invasion", "Mutual non-invasion")))), stat = "identity") +
labs(x = "Frequency", fill = "Invasion", y = "Strain 1 cue") +
theme_bw() +
scale_fill_manual(values = c("Only strain 1 invasion" = "#4575b4",
"Only strain 2 invasion" = "#fc8d59",
"Mutual invasion" = "#fee090")) +
theme(text = element_text(size = 15))
plot together
ggsave(here("figures/plos-bio/invasion_heatmap.tiff"), width = 10)
Saving 10 x 7 in image
#—— effect cue perception ——-#
static
logging
# get non-logged pairings
static_nolog <- static.df2 %>%
mutate(cue_1 = trimws(gsub("\\ .*", "", label_ci_1)),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none")) %>%
filter(log_1 == "none")
static_log <- static.df2 %>%
mutate(cue_1 = trimws(gsub("\\ .*", "", label_ci_1)),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none")) %>%
filter(log_1 == "log")
static_log.df <- left_join(
select(static_nolog, cue_1, label_ci_2, log_1, None = fitness_diff),
select(static_log, cue_1, label_ci_2, log_1, Log = fitness_diff),
by = c("cue_1", "label_ci_2")) %>%
filter(!is.na(None) & !is.na(Log)) %>%
mutate(classification = ifelse(Log > None, "Logged better", "Not logged better"))
Error in `stop_subscript()`:
! Can't subset columns that don't exist.
x Column `fitness_diff` doesn't exist.
Backtrace:
1. ... %>% ...
6. dplyr:::select.data.frame(...)
7. tidyselect::eval_select(expr(c(...)), .data)
8. tidyselect:::eval_select_impl(...)
16. tidyselect:::vars_select_eval(...)
...
23. tidyselect:::chr_as_locations(x, vars)
24. vctrs::vec_as_location(x, n = length(vars), names = vars)
25. vctrs `<fn>`()
26. vctrs:::stop_subscript_oob(...)
27. vctrs:::stop_subscript(...)
combined
static_comb.df <- left_join(
select(static_nocomb, cue_1, label_ci_2, log_1, Self = fitness_diff),
select(static_comb, cue_1, label_ci_2, log_1, Total = fitness_diff),
by = c("cue_1", "log_1", "label_ci_2")) %>%
filter(!is.na(Total) & !is.na(Self)) %>%
mutate(classification = ifelse(Total > Self, "Total better", "Self better"))
Error in `stop_subscript()`:
! Can't subset columns that don't exist.
x Column `fitness_diff` doesn't exist.
Backtrace:
1. ... %>% ...
6. dplyr:::select.data.frame(...)
7. tidyselect::eval_select(expr(c(...)), .data)
8. tidyselect:::eval_select_impl(...)
16. tidyselect:::vars_select_eval(...)
...
23. tidyselect:::chr_as_locations(x, vars)
24. vctrs::vec_as_location(x, n = length(vars), names = vars)
25. vctrs `<fn>`()
26. vctrs:::stop_subscript_oob(...)
27. vctrs:::stop_subscript(...)
plot
static_log.pl <- ggpaired(static_log.df, cond1 = "None", cond2 = "Log", line.color = "classification", alpha = 0.5) +
labs(x = "Cue perception", y = "Fitness difference", color = "Effect") +
scale_color_manual(values = c("Not logged better" = "#fc8d59", "Logged better" = "#4575b4"))
static_comb.pl <- ggpaired(static_comb.df, cond1 = "Total", cond2 = "Self", line.color = "classification", alpha = 0.5) +
labs(x = "Cue perception", y = "Fitness difference", color = "Effect") +
scale_color_manual(values = c("Total better" = "#fc8d59", "Self better" = "#4575b4"))
static_cue.pl <- ggarrange(static_log.pl, static_comb.pl, ncol = 2, align = "h")
ggsave(here("figures/plos-bio/static_cue_perception.tiff"), width = 7.5, height = 4)
invasion
proces data
# join invade df with label because I am lazy
invade.df2 <- invade.df %>%
left_join(select(ez_label, id_ci, label_ci_1 = label_ci), by = c("mut_id" = "id_ci"))
log
# get non-logged pairings
invade_nolog <- invade.df2 %>%
mutate(cue_1 = trimws(gsub("\\ .*", "", label_ci_1)),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none")) %>%
filter(log_1 == "none")
invade_log <- invade.df2 %>%
mutate(cue_1 = trimws(gsub("\\ .*", "", label_ci_1)),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none")) %>%
filter(log_1 == "log")
invade_log.df <- left_join(
select(invade_nolog, cue_1, res_id, log_1, None = fitness),
select(invade_log, cue_1, res_id, log_1, Log = fitness),
by = c("cue_1", "res_id")) %>%
filter(!is.na(None) & !is.na(Log)) %>%
mutate(classification = ifelse(Log > None, "Logged better", "Not logged better"))
combined
invade_nocomb <- invade.df2 %>%
mutate(cue_1 = ifelse(
str_detect(label_ci_1, "sum"), "I+Ig",
trimws(gsub("+1.*|\\ log", "", label_ci_1))
),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none"),
comb_1 = case_when(
str_detect(label_ci_1, "1+|sum") ~ "comb",
str_detect(label_ci_1, "1+|sum", negate = T) ~ "none"
)) %>%
filter(comb_1 == "none")
invade_comb <- invade.df2 %>%
mutate(cue_1 = ifelse(
str_detect(label_ci_1, "sum"), "I+Ig",
trimws(gsub("+1.*|\\ log", "", label_ci_1))
),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none"),
comb_1 = case_when(
str_detect(label_ci_1, "1+|sum") ~ "comb",
str_detect(label_ci_1, "1+|sum", negate = T) ~ "none"
)) %>%
filter(comb_1 == "comb")
invade_comb.df <- left_join(
select(invade_nocomb, cue_1, res_id, log_1, Self = fitness),
select(invade_comb, cue_1, res_id, log_1, Total = fitness),
by = c("cue_1", "log_1", "res_id")) %>%
filter(!is.na(Total) & !is.na(Self)) %>%
mutate(classification = ifelse(Total > Self, "Total better", "Self better"))
plot
invade_cue.pl <- ggarrange(invade_log.pl, invade_comb.pl, align = "h", ncol = 2)
ggsave(here("figures/plos-bio/invasion_cue_perception.tiff"))
Saving 7 x 7 in image
#——————————————-# # Partitioning best cue #——————————————-# #——- single infection ———–# # redo some optimization (lower fitness in no R than default)
source(here("functions/chabaudi_si_clean_R.R"))
source(here("functions/chabaudi_si_clean_N.R"))
# I none
cl <- makeCluster(detectCores()); setDefaultCluster(cl = cl)
I_no_R <- optimParallel(
par = rep(0.5,4), # start at 0.5x4
fn = chabaudi_si_clean_R,
control = list(trace = 6, fnscale = -1),
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 20, by = 1e-3),
cue_range = seq(0, 6*(10^6), by = (6*(10^6))/5000),
cue = "I",
log_cue = "none",
solver = "vode")
stopCluster(cl)
# 0.144021 -43.1046 2030.27 -524.686
# 8.69589
import and process data
# import in data
si_partition.ls <- list.files(path = here("data/partition/si/"), pattern = "*.csv", full.names = T)
si_partition.ls <- lapply(si_partition.ls, read.csv)
Warning in read.table(file = file, header = header, sep = sep, quote = quote, :
incomplete final line found by readTableHeader on '/Users/avrilwang/Desktop/Project-Plasmodium/data/partition/si//I_none_partition.csv'
si_partition.df <- do.call(rbind, si_partition.ls)
# combine with si fitness (default)
si_partition.df <- si_partition.df %>% left_join(select(si_fitness.df, id, fitness = value), by = "id")
Error in select(si_fitness.df, id, fitness = value) :
object 'si_fitness.df' not found
plot
# raw fitness
si_partition.pl1 <- ggplot() +
geom_vpline(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = mean, group = category, color = category), show.legend = F, size = 1) +
geom_point(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = value), size = 2, alpha = 0.7) +
geom_line(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = value, group = id), alpha = 0.2) +
labs(x = "Fitness", y = "Conditions") +
theme_bw()
Error in geom_vpline(data = si_partition.df2, aes(y = fct_reorder(category, :
could not find function "geom_vpline"
#——- consequences of no targeted immunity ————# # get dynamics of no targeted immunity
get_dyn <- function(df){
source(here("functions/chabaudi_si_clean_W.R"))
id <- df$id
cue <- df$cue
log <- df$log
par <- c(df$var_W1, df$var_W2, df$var_W3, df$var_W4)
cue_range <- seq(df$low, df$high, by = df$by)
# get dynamics
dyn <- chabaudi_si_clean_W(
parameters_cr = par,
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 20, by = 1e-3),
cue_range = cue_range,
cue = cue,
log_cue = log,
solver = "vode",
dyn = T
)
# combine
dyn2 <- cbind(dyn, id = id, cue = cue, log = log)
write_parquet(dyn2, paste0(here("data/partition/si_dyn/"), id, "_noW_dyn.parquet"))
}
get df to run
mclapply(si_partition.ls, get_dyn)
$`1`
$`2`
$`3`
$`4`
$`5`
$`6`
$`7`
$`8`
$`9`
$`10`
NA
process dataframe
# import in dataframe
no_W.ls <- list.files(here("data/partition/si_dyn/"), pattern = "*noW_dyn.parquet", full.names = T)
no_W.df <- lapply(no_W.ls, read_parquet)
no_W.df <- do.call(rbind, no_W.df)
# combine with ez label
ez_label <- read.csv(here("data/ez_label.csv"))
no_W.df <- left_join(no_W.df, ez_label, by = c("id" = "id_si"))
# get conversion rate
no_W.cr <- no_W.df %>% filter(variable == "cr")
no_W.I <- no_W.df %>% filter(variable == "I")
# get default conversion rate dynamics
si_dyn.df <- left_join(si_dyn.df, ez_label, by = c("id" = "id_si"))
si_dyn.cr <- si_dyn.df %>% filter(variable == "cr")
si_dyn.I <- si_dyn.df %>% filter(variable == "I")
plot conversion rate
mechanism: targeted immunity led to lower parasite density in the initial stages, which prevents parasites from making the switch from no conversion rate to high conversion rate. When parsite density undergoes drastic increase at the beginning due to lower immunity, this presents a higher degree of signal that allows parasite to make the switch appropriately
partition_cr.pl <- ggplot() +
geom_line(data = no_W.cr, aes(x = time, y= value, color = "No targeted immunity")) +
geom_line(data = si_dyn.cr, aes(x = time, y= value, color = "Default")) +
facet_wrap(~ez_label_si, ncol = 5) +
xlim(0, 20) +
geom_vline(xintercept = 7) +
labs(x = "Time (days)", y = "Conversion rate", color = "Condition") +
theme_bw()
no_W.cr
#—– cue state ————–#
function to get cue states
plot
absence of targeted immunity led to drastic increase in parasite density in early phases of infection. This produces high signal intensity for parasite and host-based cues, especially non-logged ones, which allows for state differentation. While this can be viewed as a modelling artifiact, it should be noted that the logged cues seldom changed as these changes in early infection did little to alter the actual early signal intensity sensed by the parasite. In an environment where there is heterogeneity in host response, and thus, signal, logging allows for parasites to adapt optimal strategy whereas non-logged cues must contend with sensitivity to immunity.
# arrange
pl <- ggarrange(state_pl, cr_pl, ncol = 1, nrow = 2, align = "v", heights = c(1, 0.3))
Warning: Removed 4 rows containing missing values (geom_raster).
split
# combine state
noW_default.state <- left_join(
select(no_W.state2, time, `No targeted\nimmunity` = value, id, ez_label_si),
select(default.state %>% filter(time <= 20), time, `Default` = value, id, ez_label_si), by = c("time", "id", "ez_label_si"))
noW_default.state2 <- tidyr::pivot_longer(noW_default.state, c(`No targeted\nimmunity`, `Default`))
# combine conversion raster
noW_default.cr <- left_join(
select(no_W.cr, time, `No targeted\nimmunity` = value, id, ez_label_si),
select(si_dyn.cr %>% filter(time <= 20), time, `Default` = value, id, ez_label_si), by = c("time", "id", "ez_label_si"))
noW_default.cr2 <- tidyr::pivot_longer(noW_default.cr, c(`No targeted\nimmunity`, `Default`))
# split
noW_default_state.ls <- split(noW_default.state2, noW_default.state2$id)
noW_default_cr.ls <- split(noW_default.cr2, noW_default.cr2$id)
# run function
mapply(plot_state, noW_default_state.ls, noW_default_cr.ls)
#——– reaction norms of default vs optimized ————# # get reaction norm and rug data
source(here("functions/par_to_df.R"))
# Gametocyte
g_log.rn <- par_to_df(par = c(1.211521, -3.936778, -1.312944, -1.285713), cue_range = seq(0, log10(6*(10^4)), by = (log10(6*(10^4)))/5000))
g_log.rn2 <- par_to_df(par = c(1.393860539, -4.253007616, -0.313947029, -2.000857344), cue_range = seq(0, log10(6*(10^4)), by = (log10(6*(10^4)))/5000))
g.rn <- par_to_df(par = c(0.04061288, -9.31445958, 74.13015506, -431.5984364), cue_range = seq(0, 6*(10^4), by = (6*(10^4))/5000))
g.rn2 <- par_to_df(par = c(0.541729073, -3.904616443, 0.87487412, -0.694177021), cue_range = seq(0, 6*(10^4), by = (6*(10^4))/5000))
# I+Ig
I_Ig_log.rn <- par_to_df(par = c(3.594042, 4.157744, -13.530672, 2.599905), cue_range = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/5000))
I_Ig_log.rn2 <- par_to_df(par = c(63.71893822, -87.77671601, -56.55475514, -66.02209549), cue_range = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/5000))
I_Ig.rn <- par_to_df(par = c(0.3159297, -46.1104558, 1250.752908, -6.1982093), cue_range = seq(0, 6*(10^6), by = (6*(10^6))/5000))
I_Ig.rn2 <- par_to_df(par = c(0.731982784, -21.69799449, 149.7841876, 17.02551769), cue_range = seq(0, 6*(10^6), by = (6*(10^6))/5000))
# convert log to non-logged scale
g_log.rn$cue_range <- 10^(g_log.rn$cue_range)
g_log.rn2$cue_range <- 10^(g_log.rn2$cue_range)
I_Ig_log.rn$cue_range <- 10^(I_Ig_log.rn$cue_range)
I_Ig_log.rn2$cue_range <- 10^(I_Ig_log.rn2$cue_range)
# get rug
g_log.rug <- default.state %>%
filter(label_si == "G log") %>%
mutate(value = 10^value) %>%
select(label_si, value)
g_log.rug2 <- no_W.state %>%
filter(label_si == "G log") %>%
mutate(value = 10^value) %>%
filter(value <= 6*(10^4)) %>%
select(label_si, value)
I_Ig_log.rug <- default.state %>%
filter(label_si == "I+Ig log") %>%
select(label_si, value)
I_Ig_log.rug2 <- no_W.state %>%
filter(label_si == "I+Ig log") %>%
select(label_si, value)
g.rug <- default.state %>%
filter(label_si == "G") %>%
select(label_si, value)
g.rug2 <- no_W.state %>%
filter(label_si == "G" & value <= 6*(10^4)) %>%
select(label_si, value)
I_Ig.rug <- default.state %>%
filter(label_si == "I+Ig") %>%
select(label_si, value)
I_Ig.rug2 <- no_W.state %>%
filter(label_si == "I+Ig") %>%
select(label_si, value)
# get rug limits
rug_lim <- rbind(g_log.rug,
g_log.rug2,
I_Ig_log.rug,
I_Ig_log.rug2,
g.rug,
g.rug2,
I_Ig.rug,
I_Ig.rug2) %>%
group_by(label_si) %>%
summarize(max = max(hablar::s(value), na.rm = T),
min = min(hablar::s(value), na.rm = T))
# combine and filter
rn <- rbind(
cbind(g_log.rn, label_si = "G log", condition = "Default"),
cbind(g_log.rn2, label_si = "G log", condition = "No targeted\nimmunity"),
cbind(g.rn, label_si = "G", condition = "Default"),
cbind(g.rn2, label_si = "G", condition = "No targeted\nimmunity"),
cbind(I_Ig_log.rn, label_si = "I+Ig log", condition = "Default"),
cbind(I_Ig_log.rn2, label_si = "I+Ig log", condition = "No targeted\nimmunity"),
cbind(I_Ig.rn, label_si = "I+Ig", condition = "Default"),
cbind(I_Ig.rn2, label_si = "I+Ig", condition = "No targeted\nimmunity")
) %>%
left_join(rug_lim, by = "label_si") %>%
group_by(label_si) %>%
filter(cue_range <= max & cue_range >= min)
# combine rug
rug <- rbind(cbind(g_log.rug, condition = "Default"),
cbind(g_log.rug2, condition = "No targeted\nimmunity"),
cbind(g.rug, condition = "Default"),
cbind(g.rug2, condition = "No targeted\nimmunity"),
cbind(I_Ig_log.rug, condition = "Default"),
cbind(I_Ig_log.rug2, condition = "No targeted\nimmunity"),
cbind(I_Ig.rug, condition = "Default"),
cbind(I_Ig.rug2, condition = "No targeted\nimmunity"))
# cobine with ezlabel
rn2 <- rn %>% left_join(ez_label, by = "label_si")
rug2 <- rug %>% left_join(ez_label, by = "label_si")
# filter rug
default.rug <- rug2 %>% filter(condition == "Default")
no.rug <- rug2 %>% filter(condition == "No targeted\nimmunity")
plot
ggplot() +
geom_line(data = rn2, aes(x = cue_range, y = cr, color = condition)) +
geom_rug(data = default.rug, aes(x = value, color = condition), sides = "b") +
geom_rug(data = no.rug, aes(x = value, color = condition), sides = "t") +
facet_wrap(~fct_relevel(ez_label_si, c("Gametocyte log10", "Gametocyte", "Asexual&sexual\niRBC log10", "Asexual&sexual iRBC")), scales = "free_x") +
scale_x_continuous(labels = function(x) format(x, scientific = TRUE)) +
theme_bw() +
scale_color_manual(values =c("Default" = "#4575b4", "No targeted\nimmunity" = "#fc8d59")) +
ylim(0, 1.1) +
labs(x = "Cue range", y = "Conversion rate", color = "Condition")
ggsave(here("figures/plos-bio/partition_rn.tiff"), width = 7.5, height = 6)
get conversion rate legend
noW_default.cr %>% filter(id == "G_log") %>%
ggplot() +
geom_raster(aes(x = time, y = id, fill = Default)) +
xlim(1,20) +
theme_bw() +
labs(x = "Time (days)",
fill = "Conversion rate") +
theme(axis.title.y=element_blank(),
axis.ticks.y=element_blank(),) +
scale_fill_viridis_c(lim = c(0, 1))
ggsave(here("figures/plos-bio/cr_legend.tiff"))
#——————————————-# Best cue adoption consequences #——————————————-# # get data for disease curves
# single infection dynamics
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet"))
# co-infection dynamics (mon-cue)
ci_dyn.df <- read_parquet(here("data/ci_dyn/ci_dyn.parquet"))
# dual cue dynamics
dual_dyn.df <- read_parquet(here("data/dual_cue_dyn/dual_cue_dyn.parquet"))
#——- single cue comparison —————# # process data
write_parquet(si_dc.low, here("data/disease_curve/si_dc_low.parquet"))
Error in write_parquet(si_dc.low, here("data/disease_curve/si_dc_low.parquet")) :
object 'si_dc.low' not found
plot
# plot
si_dc.pre <- ggplot() +
geom_path(data = si_dc.poor, aes(x= total, y = R, group = id), color = "dark grey", arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
labs(color = "Single infection\nhigh-performing cues", x = "Asexual & sexual iRBC", y = "RBC") +
theme_bw()+ scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1)) +
guides(shape = FALSE)
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
#———- co-infection monocue ————-#
# get relevent variables
ci_dc.df <- ci_dyn.df %>%
filter(variable == "I1" | variable == "Ig1" | variable == "R")
# morph into skinny format
ci_dc.df <- tidyr::pivot_wider(ci_dc.df, names_from = variable, values_from = value, id_cols = c(time, label)) %>%
mutate(total = I1+Ig1)
# good cue bad cue
ci_cue.dv <- ci_fitness.df %>%
mutate(classification = case_when(
value > 2.25 ~ "High-performing",
value <= 2.25 ~ "Poor-performing"
))
# join with classificaiton
ci_dc.df2 <- ci_dc.df %>% left_join(ci_cue.dv, by = "label")
# split into top erforming and poor-performing cues
ci_dc.high <- ci_dc.df2 %>% filter(classification == "High-performing")
ci_dc.poor <- ci_dc.df2 %>% filter(classification == "Poor-performing")
# join high performing with label
ci_dc.high2 <- ci_dc.high %>% left_join(ez_label, by = c("label" = "label_ci"))
Error in is.data.frame(y) : object 'ez_label' not found
plot
# plot
ci_dc.pre <- ggplot() +
geom_path(data = ci_dc.poor, aes(x= total, y = R, group = label), color = "dark grey", arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
labs(color = "Co-infection\nhigh-performing cues", x = "Asexual & sexual iRBC", y = "RBC") +
theme_bw()+ scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1)) +
guides(shape = FALSE)
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
#——— dual cue ————————–# # process data
# turn skinny
dual_dc.df <- dual_dyn.df %>%
mutate(label_alt = paste(label, "+" , label_b)) %>%
select(label_alt, time, variable, value) %>%
filter(variable == "I" | variable == "Ig" | variable == "R") %>%
distinct(label_alt, time, variable, .keep_all = T)
dual_dc.df2 <- dual_dc.df %>%
tidyr::pivot_wider(names_from = variable, values_from = value, id_cols = c(time, label_alt)) %>%
mutate(total = I+Ig)
write_parquet(dual_dc.df2, here("data/disease_curve/dual_dc.parquet"))
# good dual cue -> list of good performing dual cues that encompass wide variety of cues
selected_dual_cue <- c("R log + I log", "R + Ig log", "G log + I log", "G log + Ig log", "Ig + I log")
bad_dual_cue <- c("G + I", "R + Ig", "R log + Ig", "G + R", "G + R log", "G + Ig", "Ig + I", "R + I", "R log + I")
# get classification -> R log10 + I log10 as the only good one
dual_dc.high <- dual_dc.df2 %>% filter(label_alt %in% selected_dual_cue) %>%
mutate(label_alt = gsub("log", "log10", label_alt))
dual_dc.poor <- dual_dc.df2 %>% filter(label_alt %in% bad_dual_cue) %>%
mutate(label_alt = gsub("log", "log10", label_alt))
#write_parquet(dual_dc.high, here("data/disease_curve/dual_dc_high.parquet"))
#write_parquet(dual_dc.poor, here("data/disease_curve/dual_dc_poor.parquet"))
plot
dual_dc.pre <- ggplot() +
geom_path(data = dual_dc.poor, aes(x= total, y = R, group = label_alt), color = "dark grey", arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
labs(color = "High-performing\ndual cues", x = "Asexual & sexual iRBC", y = "RBC") +
theme_bw()+ scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1)) +
guides(shape = FALSE)
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
#——— co-infection static —————-#
# import in dynamics data
static_dyn.ls <- list.files(path = here("data/ci_static/"), pattern = "*.parquet", full.names = T)
static_dyn.ls <- lapply(static_dyn.ls, read_parquet)
# filter variable and transform
static_dyn.ls2 <- mclapply(static_dyn.ls, function(x){
x %>%
filter(variable == "I1" | variable == "Ig1" | variable == "I2" | variable == "Ig2" | variable == "R") %>%
mutate(id_alt = paste(id_1, id_2)) %>%
tidyr::pivot_wider(names_from = variable, values_from = value, id_cols = c(time, id_alt)) %>%
mutate(total1 = I1+Ig1, total2 = I2+Ig2)
})
static_dc.df <- do.call(rbind, static_dyn.ls2)
static_dc.df <- static_dc.df %>%
mutate(id_1 = gsub(" .*", "", id_alt),
id_2 = gsub(".* ", "", id_alt)) %>%
filter(id_1 != id_2)
#write_parquet(static_dc.df, here("data/disease_curve/static_dc.parquet"))
further processing
static_dc.df <- read_parquet(here("data/disease_curve/static_dc.parquet"))
# get winners and losers
## import in fitness
static_fitness.df <- read.csv(here("data/ci_static.csv"))
## get winner situation
static_fitness.df2 <- static_fitness.df %>%
filter(id_1 != id_2) %>%
mutate(winning_id = case_when(
fitness_difference > 0 ~ id_1,
fitness_difference< 0 ~ id_2
),
losing_id = case_when(
fitness_difference < 0 ~ id_1,
fitness_difference> 0 ~ id_2
))
# left join
static_dc.df2 <- static_dc.df %>%
left_join(select(static_fitness.df2, id_1, id_2, winning_id, losing_id, fitness_difference), by = c("id_1", "id_2"))
# get winner-loser difference in terms of I+Ig also filter out to onyl very strong fitness difference
static_dc.df3 <- static_dc.df2 %>%
mutate(total_diff = case_when(
fitness_difference > 0 ~ total1-total2,
fitness_difference< 0 ~ total2-total2
),
total_winner = case_when(
fitness_difference > 0 ~ total1,
fitness_difference< 0 ~ total2
),
total_loser = case_when(
fitness_difference > 0 ~ total2,
fitness_difference< 0 ~ total1
)) %>%
filter(abs(fitness_difference) > 0.5)
plot
static_dc.pl <- ggplot() +
geom_path(data = static_dc.df3, aes(x= total_winner, y = R, group = id_alt, color = "Winner"), alpha = 0.5, arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
geom_path(data = static_dc.df3, aes(x= total_loser, y = R, group = id_alt, color = "Loser"),
alpha = 0.5,arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
labs(color = "Status", x = "Asexual & sexual iRBC", y = "RBC") +
scale_color_manual(values=c("Winner" = "#4575b4","Loser"= "#fc8d59")) +
theme_bw() +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1))
#———co-infection invasion —————# # get invasion dynamic
# get invasion df
invasion_fitness.df <- read.csv(here("data/ci_invasion.csv"))
# get cue range
ci_cue_range <- read.csv(here("data/cue_range_ci.csv"))
invasion_fitness.df2 <- invasion_fitness.df %>%
left_join(select(ci_cue_range, id, mut_cue = cue, mut_low = low, mut_high = high, mut_by = by), by = c("mut_id"= "id")) %>%
left_join(select(ci_cue_range, id, res_cue = cue, res_low = low, res_high = high, res_by = by), by = c("res_id"= "id"))
function to get dynamic
get_invasion_dyn <- function(df){
# get cues
mut_cue <- df$mut_cue
res_cue <- df$res_cue
# get info of cues (for co infection)
if(stringr::str_detect(mut_cue, "-i")){mut_cue = gsub("*-i", "1", mut_cue)}
if(stringr::str_detect(mut_cue, "-i", negate = T)){mut_cue = mut_cue}
if(stringr::str_detect(res_cue, "-i")){res_cue = gsub("*-i", "2", res_cue)}
if(stringr::str_detect(res_cue, "-i", negate = T)){res_cue = res_cue}
# get log
mut_log <- ifelse(stringr::str_detect(df$mut_id, "log"), "log10", "none")
res_log <- ifelse(stringr::str_detect(df$res_id, "log"), "log10", "none")
# get parameters
mut_par <- c(df$mut_var1_opt, df$mut_var2_opt, df$mut_var3_opt, df$mut_var4_opt)
res_par <- c(df$res_var1, df$res_var2, df$res_var3, df$res_var4)
# get cue range
mut_cue_range <- seq(df$mut_low, df$mut_high, by = df$mut_by)
res_cue_range <- seq(df$res_low, df$res_high, by = df$res_by)
# get dynamics of co infection
ci_dyn <- chabaudi_ci_clean(
parameters_cr_1 = mut_par,
parameters_cr_2 = res_par,
immunity = "tsukushi",
parameters = parameters_tsukushi,
cue_1 = mut_cue,
cue_2 = res_cue,
cue_range_1 = mut_cue_range,
cue_range_2 = res_cue_range,
log_cue_1 = mut_log,
log_cue_2 = res_log,
solver = "vode",
time_range = seq(0, 30, 0.001),
dyn = T)
# append label to all df
ci_dyn2 <- cbind(ci_dyn, mut_id = df$mut_id, res_id = df$res_id)
# write
write_parquet(ci_dyn2, paste0(here("data/ci_invasion_dyn/"), df$mut_id, "-", df$res_id, ".parquet"))
}
run dynamic funciton
# get function and parameters
source(here("functions/chabaudi_ci_clean.R"))
parameters_tsukushi <- c(R1 = 8.89*(10^6), # slightly higher
lambda = 3.7*(10^5),
mu = 0.025,
p = 8*(10^-6), # doubled form original
alpha = 1,
alphag = 2,
beta = 5.721,
mum = 48,
mug = 4,
I0 = 43.85965,
Ig0 = 0,
a = 150,
b = 100,
sp = 1,
psin = 16.69234,
psiw = 0.8431785,
phin = 0.03520591,
phiw = 550.842,
iota = 2.18*(10^6),
rho = 0.2627156)
# split
invasion.ls <- split(invasion_fitness.df2, seq(nrow(invasion_fitness.df2)))
# run function
mclapply(invasion.ls, get_invasion_dyn, mc.cores = 4)
process data
# import in invasion dynamics
invasion_dyn.ls <- list.files(path = here("data/ci_invasion_dyn"), pattern = "*.parquet", full.names = T)
invasion_dyn.ls <- lapply(invasion_dyn.ls, read_parquet)
# filter and so on
invasion_dyn.ls2 <- mclapply(invasion_dyn.ls[167:177], mc.cores = 4, function(x){
x2 <- x %>%
filter(variable == "I1" | variable == "Ig1" | variable == "I2" | variable == "Ig2" | variable == "R") %>%
mutate(id_alt = paste(mut_id, res_id)) %>%
select(id_alt, time, variable, value) %>%
tidyr::pivot_wider(names_from = variable, values_from = value, id_cols = c(time, id_alt)) %>%
mutate(total1 = I1+Ig1, total2 = I2+Ig2)
write_parquet(x2, paste0(here("data/disease_curve/ci_invasion/"), unique(x2$id_alt), "_dc.parquet"))
})
# fetch data
invasion_dyn.ls2 <- list.files(path = here("data/disease_curve/ci_invasion"), pattern = "*.parquet", full.names = T)
invasion_dyn.ls2 <- lapply(invasion_dyn.ls2, read_parquet)
invasion_dc.df <- do.call(rbind, invasion_dyn.ls2)
invasion_dc.df <- invasion_dc.df %>%
mutate(mut_id = gsub(" .*", "", id_alt),
res_id = gsub(".* ", "", id_alt)) %>%
filter(mut_id != res_id)
#write_parquet(invasion_dc.df, here("data/disease_curve/invasion_dc.parquet"))
further processing
invasion_dc.df <- read_parquet(here("data/disease_curve/invasion_dc.parquet"))
# get winners and losers
invasion_fitness.df <- read.csv(here("data/ci_invasion.csv"))
invasion_dc.df2 <- invasion_dc.df %>%
left_join(invasion_fitness.df, by = c("mut_id", "res_id")) %>%
mutate(
total_winner = case_when(
fitness> 0 ~ total1,
fitness< 0 ~ total2
),
total_loser = case_when(
fitness > 0 ~ total2,
fitness < 0 ~ total1
)) %>%
filter(abs(fitness) > 0.5)
plot
invasion_dc.pl <- ggplot() +
geom_path(data = invasion_dc.df2, aes(x= total_winner, y = R, group = id_alt, color = "Winner"), alpha = 0.5, arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
geom_path(data = invasion_dc.df2, aes(x= total_loser, y = R, group = id_alt, color = "Loser"),
alpha = 0.5,arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
labs(color = "Status", x = "Asexual & sexual iRBC", y = "RBC") +
scale_color_manual(values=c("Winner" = "#4575b4","Loser"= "#fc8d59")) +
theme_bw() +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE, accuracy = 0.1)) %>%
theme(legend.position = "none")
Error in `merge_element()`:
! No method for merging ScaleContinuousPosition into element_line
Backtrace:
1. ggplot2:::`+.gg`(...)
2. ggplot2:::add_ggplot(e1, e2, e2name)
4. ggplot2:::ggplot_add.theme(object, p, objectname)
5. ggplot2:::add_theme(plot$theme, object)
7. ggplot2:::merge_element.default(t2[[item]], t1[[item]])
#——— plot disease curves together ————#
dc.pl1 <- ggarrange(si_dc.pl, ci_dc.pl, dual_dc.pl, ncol = 3, align = "h", labels = c("A", "B", "C"), widths = c(1.1, 0.9, 1.1))
Warning: stack imbalance in 'lapply', 97 then 98
Warning: stack imbalance in 'lapply', 84 then 85
Warning: stack imbalance in 'lapply', 71 then 72
#——— quantifying disease curve area ————# # function to calculate area between sets of points -> from https://stackoverflow.com/questions/3672260/area-covered-by-a-point-cloud-with-r
library(splancs)
cha<-function(df){
x <- df$total
y <- df$R
chull(x,y)->i
return(areapl(cbind(x[i],y[i])))
}
loop to get area: single infection
coinfection
# edit and join
ci_dc_high.area2 %>% ci_dc_high.area %>%
select(area, value) %>%
mutate(condition = "Co-infection")
Error in ci_dc_high.area(.) : could not find function "ci_dc_high.area"
dual cue
#—— get fitted scatter plot for all single infection, co infection, and dual cue ——–#
# plot
ggplot() +
geom_point(data = dc.area, aes(x = area, y = value)) +
facet_wrap(~condition, scales = "free") +
geom_smooth(data = dc.area, method = "lm", alpha = .15, aes(x = area, y = value), color = "#4575b4") +
labs(x = "Area", y = "Fitness", color = "Status") +
theme_bw()
`geom_smooth()` using formula 'y ~ x'

#——- plot together with disease curve ——–#
ggarrange(si_dc.pl, ci_dc.pl, dual_dc.pl, dc_area.pl1, labels = c("A", "B", "C", "D"), align = "h", ncol = 4, widths = c(1, 0.9, 1, 1.5))
`geom_smooth()` using formula 'y ~ x'
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.

ggarrange(si_dc.pl, ci_dc.pl, dual_dc.pl, dc_area.pl1, labels = c("A", "B", "C", "D"), align = "h", ncol = 4, widths = c(1, 0.9, 1, 1.5))
`geom_smooth()` using formula 'y ~ x'
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.
ggsave(here("figures/plos-bio/disease_curve1.tiff"), units = "px", width = 2250, height = 600, scale = 2.5, dpi=300, compression = "lzw")

#——— static area comparison ————-# # compute area
# get winner and loser
static_dc.df4 <- static_dc.df %>%
left_join(select(static_fitness.df, id_1, id_2, fitness_difference), by = c("id_1", "id_2")) %>%
filter(id_1 != id_2) %>%
mutate(
total_winner = case_when(
fitness_difference > 0 ~ total1,
fitness_difference< 0 ~ total2
),
total_loser = case_when(
fitness_difference > 0 ~ total2,
fitness_difference< 0 ~ total1
))%>%
filter(fitness > 0.5)
Error in `h()`:
! Problem with `filter()` input `..1`.
ℹ Input `..1` is `fitness > 0.5`.
x object 'fitness' not found
Backtrace:
1. ... %>% filter(fitness > 0.5)
7. base::.handleSimpleError(...)
8. dplyr h(simpleError(msg, call))
plot static

#——— invasion area comparison —————–# # get area
# pair
invasion.area <- cbind(select(invasion_win.area, Winner = area),
select(invasion_loser.area, Loser = area)) %>%
mutate(classification = ifelse(Winner>Loser, "Winner larger area", "Loser larger area"))
Error in select(invasion_loser.area, Loser = area) :
object 'invasion_loser.area' not found
plot

#—— plot together ————-#

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShkZVNvbHZlKQpsaWJyYXJ5KGNyb25lKQpsaWJyYXJ5KG9wdGltUGFyYWxsZWwpCmxpYnJhcnkoZG9QYXJhbGxlbCkKbGlicmFyeShkb1JORykKbGlicmFyeShhcnJvdykKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHBhcmFsbGVsKQpsaWJyYXJ5KGdncHVicikKYGBgCgpOb3RlYm9vayBmb3IgcGxvdHRpbmcgYWxsIG9mIHRoZSBmaWd1cmVzIGZvciBQbG9TIEJpb2xvZ3kgbWFudXNjcmlwdCBzdWJtaXNzaW9uCgpHdWlkZWxpbmVzOiB0YWtlbiBmcm9tIGh0dHBzOi8vam91cm5hbHMucGxvcy5vcmcvcGxvc2Jpb2xvZ3kvcy9maWd1cmVzI2xvYy1maWd1cmUtZmlsZS1yZXF1aXJlbWVudHMKMS4gZm9ybWF0OiB0aWZmCjIuIG1heCBmaWxlIHNpemU6IDEwIE1CCjMuIHRleHQgc2l6ZTogQXJpYWwsIFRpbWVzLCBvciBTeW1ib2wgZm9udCBvbmx5IGluIDgtMTIgcG9pbnQKMi4gZmlndXJlIHNpemU6IFdpZHRoOiA3ODkg4oCTIDIyNTAgcGl4ZWxzIChhdCAzMDAgZHBpKS4gSGVpZ2h0IG1heGltdW06IDI2MjUgcGl4ZWxzIChhdCAzMDAgZHBpKS4KCiMgb3ZlcmFsbCBtYW51c2NyaXB0IHNldHVwCjEuIEZpZyAxOiBtb2RlbCBzY2hlbWF0aWMKMi4gRmlnIDIuIGJlc3Qgc2luZ2xlIGFuZCBjby1pbmZlY3Rpb24gaW5mZWN0aW9uIGN1ZSBbbW9ub2N1ZV0gLS0tLS0tLT4gc3VwcGxtZW50YXJ5IHRhYmxlIG9mIHBhcmFtZXRlcnMgYW5kIGZpdG5lc3MKMy4gRmlnIDMuIGR1YWwgY3VlIG9wdGltaXphdGlvbiBbbW9ub2N1ZV0gLS0tLS0tLT4gc3VwcGxlbWVudGFyeSB0YWJsZSBvZiBmbGV4aWJsZSBvcHRpbWl6YXRpb24KNC4gRmlnIDQuIGhldGVyb2N1ZSBjb21wZXRpdGlvbiBbaGV0ZXJvY3VlXSAKNS4gRmlnIDUuIHBhcnRpdGlvbmluZyBzaW5nbGUgY3VlIHN1Y2Nlc3MgYW5kIGNvbnNlcXVlbmNlcyBvZiBib3R0b20rdG9wIGRvd24gcmVndWxhdGlvbiBbbW9ub2N1ZV0KNi4gRmlnIDYuIGNvbnNlcXVlbmNlcyBvZiBhZG9wdGluZyBiZXN0IGN1ZSBbbW9ub2N1ZV0KCgojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCmJlc3Qgc2luZ2xlIGFuZCBjby1pbmZlY3Rpb24gY3VlCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSMKRmlndXJlIGRpc3BsYXlpbmcgdGhlIHJlYWN0aW9uIG5vcm1zIG9mIGJlc3Qgc2luZ2xlIGFuZCBjby1pbmZlY3Rpb24uCgojLS0tLS0tLSBvcHRpbWFsIGN1ZSByZWFjdGlvbiBub3JtIC0tLS0tLS0tLS0tIwojIHJlYWQgZGF0YQpgYGB7cn0KIyBzaW5nbGUgaW5mZWN0aW9uIGR5bmFtaWNzLCByZWFjdGlvbiBub3JtcywgYW5kIHJ1Z3MKc2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9keW5fMzAucGFycXVldCIpKSAKc2lfcm4uZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvc2lfZHluL3NpX3JuLnBhcnF1ZXQiKSkKc2lfcnVnLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9ydWcucGFycXVldCIpKQoKIyBjby1pbmZlY3Rpb24gZHluYW1pY3MsIHJlYWN0aW9uIG5vcm1zLCBhbmQgcnVncwpjaV9keW4uZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvY2lfZHluL2NpX2R5bi5wYXJxdWV0IikpCmNpX3JuLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2NpX2R5bi9jaV9ybi5wYXJxdWV0IikpCmNpX3J1Zy5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9jaV9keW4vY2lfcnVnLnBhcnF1ZXQiKSkKYGBgCgojIHByb2Nlc3MgZGF0YSBmb3IgcmVhY3Rpb24gbm9ybQpgYGB7cn0KIyBpbXBvcnQgbGFiZWxsaW5nIHNjaGVtZQplel9sYWJlbCA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2V6X2xhYmVsLmNzdiIpKQoKIyBnZXQgc2lfbGFiZWwgd2l0aCBjaSBjdWUgcmFuZ2UKc2lfY2lfcnVnLmRmIDwtIGNpX3J1Zy5kZiAlPiUgCiAgbXV0YXRlKGxhYmVsX3NpID0gY2FzZV93aGVuKAogICAgbGFiZWwgJWluJSBjKCJJIiwgIkkxK0kyIikgfiAiSSIsCiAgICBsYWJlbCAlaW4lIGMoIkkgbG9nIiwiSTErSTIgbG9nIikgfiAiSSBsb2ciLAogICAgbGFiZWwgJWluJSBjKCJJZyIsICJJZzErSWcyIikgfiAiSWciLAogICAgbGFiZWwgJWluJSBjKCJJZyBsb2ciKSB+ICJJZyBsb2ciLAogICAgbGFiZWwgJWluJSBjKCJzdW0iLCAiSStJZyIpIH4gIkkrSWciLAogICAgbGFiZWwgJWluJSBjKCJzdW0gbG9nIiwgIkkrSWcgbG9nIikgfiAiSStJZyBsb2ciLAogICAgbGFiZWwgPT0gIlIiIH4gIlIiLAogICAgbGFiZWwgPT0gIlIgbG9nIiB+ICJSIGxvZyIsCiAgICBsYWJlbCAlaW4lIGMoIkciLCAiRzErRzIiKSB+ICJHIiwKICAgIGxhYmVsID09ICJHIGxvZyIgfiAiRyBsb2ciCiAgKSkgCgojIGdldCBsaW1pdCBmb3Igc2lfcnVnCnNpX3J1Z19saW0uZGYgPC0gc2lfcnVnLmRmICU+JSAKICBmaWx0ZXIodGltZSA8PSAyMCkgJT4lCiAgZ3JvdXBfYnkobGFiZWwpJT4lIAogIHN1bW1hcmlzZShtaW4gPSBtaW4odmFsdWUsIG5hLnJtID0gVCkqMC45LAogICAgICAgICBtYXggPSBtYXgodmFsdWUsIG5hLnJtID0gVCkqMS4xKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpID0gbGFiZWwsIG1pbl9zaSA9IG1pbiwgbWF4X3NpID0gbWF4KQoKIyBmaWx0ZXIgdG8gcmVzdHJpY3Rpb24gY29udmVyc2lvbiByYXRlIHJlYWN0aW9uIG5vcm0gcmFuZ2UgdG8gY3VlIHJhbmdlcyB0aGF0IGFwcGVhciBpbiBydWcKIyMgY2hhbmdlIHRvIEluZi8taW5mIHRvIE5BLiBOb3RlIHRoYXQgSSBhbSBmaXJzdCBqb2luaW5nIHdpdGggc2kgcnVnIGxpbSB0byBjaGVjayB3aGljaCBsaW1pdCBpcyBsYXJnZXIsIFdlIHdpbGwgZ28gd2l0aCB0aGUgY3VlIHJhbmdlIHRoYXQgaGFzIHRoZSBsYXJnZXN0IHNwYW4KY2lfcnVnX2xpbS5kZiA8LSBzaV9jaV9ydWcuZGYgJT4lIAogIGdyb3VwX2J5KGxhYmVsKSAlPiUgCiAgbXV0YXRlKG1pbiA9IG1pbih2YWx1ZSwgbmEucm0gPSBUKSowLjksCiAgICAgICAgIG1heCA9IG1heCh2YWx1ZSwgbmEucm0gPSBUKSoxLjEpICU+JSAKICBkaXN0aW5jdChsYWJlbCwgLmtlZXBfYWxsID0gVCkgJT4lIAogIHNlbGVjdChsYWJlbCwgbGFiZWxfc2ksIG1pbiwgbWF4KQoKcnVnX2xpbS5maW5hbCA8LSBjaV9ydWdfbGltLmRmICU+JSBsZWZ0X2pvaW4oc2lfcnVnX2xpbS5kZiwgYnkgPSAibGFiZWxfc2kiKSAlPiUgCiAgbXV0YXRlKGZpbmFsX21pbiA9IG1pbihtaW4sIG1pbl9zaSksCiAgICAgICAgIGZpbmFsX21heCA9IG1heChtYXgsIG1heF9zaSkpCgojIGdldCBzZWNvbmQgcnVnX2xpbS5maW5hbCBmb3Igc2luZ2xlIGluZmVjdGlvbgpydWdfbGltLmZpbmFsMiA8LSBydWdfbGltLmZpbmFsICU+JSAKICBncm91cF9ieShsYWJlbF9zaSkgJT4lIAogIG11dGF0ZShmaW5hbF9taW4gPSBtaW4oZmluYWxfbWluLCBuYS5ybSA9IFQpLAogICAgICAgICBmaW5hbF9tYXggPSBtYXgoZmluYWxfbWF4LCBuYS5ybSA9IFQpKQoKIyBmaWx0ZXIgY2lfcm4gYnkgbGltaXQKY2lfcm4uZGYyIDwtIGNpX3JuLmRmICU+JSAKICBsZWZ0X2pvaW4ocnVnX2xpbS5maW5hbCwgYnkgID0gImxhYmVsIikgJT4lIAogIGdyb3VwX2J5KGxhYmVsKSAlPiUgCiAgZmlsdGVyKGN1ZV9yYW5nZSA8PSBmaW5hbF9tYXggJiBjdWVfcmFuZ2UgPj0gZmluYWxfbWluKQpgYGAKCiMgbWF0Y2ggc2luZ2xlIGluZmVjdGlvbiBybiB3aXRoIGNvaW5mZWN0aW9uIApgYGB7cn0KIyBnZXQgY2kgbGFiZWwgdG8gc2kgcnVnIGFuZCBmaWx0ZXIgYnkgbGltaXQKc2lfcm4uZGYyIDwtIGxlZnRfam9pbihzaV9ybi5kZiwgc2VsZWN0KGV6X2xhYmVsLCBsYWJlbF9zaSwgbGFiZWxfY2kpLCBieSA9IGMoImxhYmVsIiA9ICJsYWJlbF9zaSIpKSAlPiUgCiAgbGVmdF9qb2luKHJ1Z19saW0uZmluYWwsIGJ5ICA9IGMoImxhYmVsX2NpIiA9ICJsYWJlbCIpKSAlPiUgCiAgZ3JvdXBfYnkobGFiZWxfY2kpICU+JSAKICBmaWx0ZXIoY3VlX3JhbmdlIDw9IGZpbmFsX21heCAmIGN1ZV9yYW5nZSA+PSBmaW5hbF9taW4pICU+JSAKICBzZWxlY3QoY3VlX3JhbmdlLCBjciwgbGFiZWxfY2ksIGxhYmVsX3NpKQoKIyBnZXQgY2kgbGFiZWwgdG8gc2kgcnVnCnNpX3J1Zy5kZjIgPC0gc2VsZWN0KHNpX3J1Zy5kZiwgdmFsdWUsIGxhYmVsX3NpID0gbGFiZWwpIApgYGAKCgojIHBsb3QgcmVhY3Rpb24gbm9ybQpgYGB7cn0KIyBqb2luIHdpdGggZXpsYWJlbApjaV9ybi5kZjMgPC0gY2lfcm4uZGYyICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gYygibGFiZWwiID0gImxhYmVsX2NpIikpCnNpX3JuLmRmMyA8LSBzaV9ybi5kZjIgJT4lIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSAibGFiZWxfY2kiKQpjaV9ydWcuZGYzIDwtIGNpX3J1Zy5kZiAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9IGMoImxhYmVsIiA9ICJsYWJlbF9jaSIpKQpzaV9ydWcuZGYzIDwtIHNpX3J1Zy5kZjIgJT4lIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSAibGFiZWxfc2kiKQoKIyByZWRvIG9yZGVyIG9mIGN1ZXMKY2lfcm4uZGYzJGxhYmVsIDwtIGZhY3RvcihjaV9ybi5kZjMkbGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJJIiwgIkkgbG9nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSTErSTIiLCAiSTErSTIgbG9nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSWciLCAiSWcgbG9nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSStJZyIsICJJK0lnIGxvZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInN1bSIsICJzdW0gbG9nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRyIsICJHIGxvZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkcxK0cyIiwgIklnMStJZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSIiwgIlIgbG9nIikpIAoKc2lfcm4uZGYzJGxhYmVsX2NpIDwtIGZhY3RvcihzaV9ybi5kZjMkbGFiZWxfY2ksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJJIiwgIkkgbG9nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSTErSTIiLCAiSTErSTIgbG9nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSWciLCAiSWcgbG9nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSStJZyIsICJJK0lnIGxvZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInN1bSIsICJzdW0gbG9nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRyIsICJHIGxvZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkcxK0cyIiwgIklnMStJZzIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSIiwgIlIgbG9nIikpCgpjaV9ydWcuZGYzJGxhYmVsIDwtIGZhY3RvcihjaV9ydWcuZGYzJGxhYmVsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiSSIsICJJIGxvZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkkxK0kyIiwgIkkxK0kyIGxvZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnIiwgIklnIGxvZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkkrSWciLCAiSStJZyBsb2ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzdW0iLCAic3VtIGxvZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkciLCAiRyBsb2ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHMStHMiIsICJJZzErSWcyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUiIsICJSIGxvZyIpKQoKc2lfcnVnLmRmMyRsYWJlbF9jaSA8LSBmYWN0b3Ioc2lfcnVnLmRmMyRsYWJlbF9jaSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkkiLCAiSSBsb2ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJMStJMiIsICJJMStJMiBsb2ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJZyIsICJJZyBsb2ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJK0lnIiwgIkkrSWcgbG9nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic3VtIiwgInN1bSBsb2ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHIiwgIkcgbG9nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRzErRzIiLCAiSWcxK0lnMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlIiLCAiUiBsb2ciKSkKCiMgcGxvdApvcHRfY3VlX3BsLkEgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gY2lfcm4uZGYzLCBhZXMoeCA9IGN1ZV9yYW5nZSwgeSA9IGNyLCBjb2xvciA9ICJDby1pbmZlY3Rpb24iKSkgKwogIGdlb21fbGluZShkYXRhID0gc2lfcm4uZGYzLCBhZXMoeCA9IGN1ZV9yYW5nZSwgeSA9IGNyLCBjb2xvciA9ICJTaW5nbGUgaW5mZWN0aW9uIiksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3J1ZyhkYXRhID0gY2lfcnVnLmRmMywgYWVzKHggPSB2YWx1ZSksIGNvbG9yID0gIiM0NTc1YjQiLCBzaWRlcyA9ICJ0IikgKwogIGdlb21fcnVnKGRhdGEgPSBzaV9ydWcuZGYzLCBhZXMoeCA9IHZhbHVlKSwgY29sb3IgPSAiI2ZjOGQ1OSIsIHNpZGVzID0gImIiKSArCiAgZmFjZXRfd3JhcCh+ZXpfbGFiZWwsIHNjYWxlcyA9ICJmcmVlX3giLCBuY29sID0gMikgKwogIHRoZW1lX2J3KCkgKwogIGxhYnMoeSA9ICJDb252ZXJzaW9uIHJhdGUiLCB4ID0gIkN1ZSByYW5nZSIsIGNvbG9yID0gIkluZmVjdGlvbiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUKSwKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGNoZWNrLm92ZXJsYXAgPSBUUlVFKSkgKyAKICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gNykpICArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCAiIzQ1NzViNCIsICIjZmM4ZDU5IikpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9yZWFjdGlvbl9ub3JtLnBuZyIpLCB3aWR0aCA9IDcsIGhlaWdodCA9IDEwKQpgYGAKCiMtLS0tLS0tLS0tIHBsb3QgYmVzdCBmaXRuZXNzIC0tLS0tLS0tLS0tLS0tIwojIGltcG9ydCBpbiBkYXRhCmBgYHtyfQojIHNpbmdsZSBpbmZlY3Rpb24gZHluYW1pY3MKc2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9keW5fMzAucGFycXVldCIpKSAKCiMgY28taW5mZWN0aW9uIGR5bmFtaWNzCmNpX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9jaV9keW4vY2lfZHluLnBhcnF1ZXQiKSkKCmV6X2xhYmVsIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvZXpfbGFiZWwuY3N2IikpCmBgYAoKIyBwcm9jZXNzIGZvciBmaW5hbCAyMCBkYXlzIGZpdG5lc3MKYGBge3J9CiMgZ2V0IHNpbmdsZSBpbmZlY3Rpb24gbWF4aW11bSB0YXVfY3VtIGZvciAyMCBkYXlzCnNpX2ZpdG5lc3MuZGYgPC0gc2lfZHluLmRmICU+JSAKICBmaWx0ZXIodmFyaWFibGUgPT0gInRhdV9jdW0iICYgdGltZSA9PSAyMCkKCiMgZ2V0IGNvLWluZmVjdGlvbiBtYXhpbXVtIHRhdV9jdW0gZm9yIDIwIGRheXMKY2lfZml0bmVzcy5kZiA8LSBjaV9keW4uZGYgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAidGF1X2N1bTEiICYgdGltZSA9PSAyMCkKCiMgam9pbiB0b2dldGhlciB0d28gZGF0YWZyYW1lcyBhbmQgYWRkIGxhYmVscwpzaV9jaV9maXRuZXNzLmRmIDwtIHNlbGVjdChjaV9maXRuZXNzLmRmLCBmaXRuZXNzX2NpID0gdmFsdWUsIGxhYmVsX2NpID0gbGFiZWwpICU+JSAKICBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gImxhYmVsX2NpIikgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc2lfZml0bmVzcy5kZiwgZml0bmVzc19zaSA9IHZhbHVlLCBpZF9zaSA9IGlkKSwgYnkgPSAiaWRfc2kiKQpgYGAKCiMgcGxvdApgYGB7cn0Kb3B0X2N1ZV9wbC5CIDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSBzaV9jaV9maXRuZXNzLmRmLCBhZXMoeCA9IGZpdG5lc3Nfc2ksIHkgPSBmaXRuZXNzX2NpLCBjb2xvciA9IGV6X2xhYmVsX3NpLCBzaGFwZSA9IGV6X2xhYmVsX3NpKSwgc2l6ZSA9IDIuNSkgKwogIGdncmVwZWw6Omdlb21fbGFiZWxfcmVwZWwoZGF0YSA9IHNpX2NpX2ZpdG5lc3MuZGYsIGFlcyhsYWJlbCA9IGV6X2xhYmVsLCB4ID0gZml0bmVzc19zaSwgeSA9IGZpdG5lc3NfY2kpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJ3aGl0ZSIseGxpbSA9IGMoLUluZiwgSW5mKSwgeWxpbSA9IGMoTkEsIE5BKSkgKwogIGxhYnMoeCA9ICJPcHRpbWFsIHNpbmdsZS1pbmZlY3Rpb24gZml0bmVzcyIsIHkgPSAiT3B0aW1hbCBDby1pbmZlY3Rpb24gZml0bmVzcyAocGVyIHN0cmFpbikiLAogICAgICAgY29sb3IgPSAiU2luZ2xlIGluZmVjdGlvbiBjdWUiLCBzaGFwZSA9ICJTaW5nbGUgaW5mZWN0aW9uIGN1ZSIpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gMTU6MjQpICsKICBsaW1zKHggPSBjKDgsIDEwLjUpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gOS4yLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBhbHBoYSA9IDAuNSkgKyAjIHNpIGdvb2QgY3VlIGN1dG9mZgogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDIuMjUsIGxpbmV0eXBlID0gImRhc2hlZCIsIGFscGhhID0gMC41KSArICMgY2kgZ29vZCBjdWUgY3V0b2ZmCiAgdGhlbWVfYncoKSArCiAgY29vcmRfY2FydGVzaWFuKGNsaXAgPSAib2ZmIikgKwogIHRoZW1lKHBsb3QubWFyZ2luPW1hcmdpbihyPTApKQpgYGAKCiMtLS0tLS0tLS0tLS0tLSB0aW1lc2VyaWVzIGNvbnZlcnNpb24gcmF0ZSAtLS0tLS0tLS0tLS0tLS0tLSMKIyBwcm9jZXNzIGluZm8gZm9yIHNpbmdsZSBpbmZlY3Rpb24KYGBge3J9CiMgZ2V0IGZpbnRlc3MKc2lfY3IuZGYgPC0gc2lfZHluLmRmICU+JSAKICBmaWx0ZXIodGltZSA8PSAyMCAmIHZhcmlhYmxlID09ICJjciIpCgojIGdvb2QgY3VlIGJhZCBjdWUKc2lfY3VlLmR2IDwtIHNpX2ZpdG5lc3MuZGYgJT4lIAogIG11dGF0ZShjbGFzc2lmaWNhdGlvbiA9IGNhc2Vfd2hlbigKICAgIHZhbHVlID4gOS4yIH4gIkhpZ2gtcGVyZm9ybWluZyIsCiAgICB2YWx1ZSA8PSA5LjIgfiAiUG9vci1wZXJmb3JtaW5nIgogICkpCgojIGpvaW4gd2l0aCBjbGFzc2lmaWNhaXRvbgpzaV9jci5kZjIgPC0gc2lfY3IuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc2lfY3VlLmR2LCBpZCwgY2xhc3NpZmljYXRpb24sIGZpdG5lc3Nfc2kgPSB2YWx1ZSksIGJ5ID0gImlkIikgJT4lIAogIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkKCiMgc3BsaXQgaW50byB0b3AgZXJmb3JtaW5nIGFuZCBwb29yLXBlcmZvcm1pbmcgY3VlcwpzaV9jci5oaWdoIDwtIHNpX2NyLmRmMiAlPiUgZmlsdGVyKGNsYXNzaWZpY2F0aW9uID09ICJIaWdoLXBlcmZvcm1pbmciKQpzaV9jci5wb29yIDwtIHNpX2NyLmRmMiAlPiUgZmlsdGVyKGNsYXNzaWZpY2F0aW9uID09ICJQb29yLXBlcmZvcm1pbmciKQoKc2lfY3VlLmR2CmBgYAoKIyBwbG90IHNpbmdsZSBpbmZlY3Rpb24gY29udmVyc2lvbiByYXRlIGhlYXRtYXAKYGBge3J9CiMgcGxvdCBwb29yIHBlcmZvcm1pbmcKc2lfY3IucGwxIDwtIGdncGxvdCgpICsKICBnZW9tX3RpbGUoZGF0YSA9IHNpX2NyLnBvb3IsIGFlcyh4ID0gdGltZSwgeSA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGV6X2xhYmVsX3NpLCBmaXRuZXNzX3NpKSwgZmlsbCA9IHZhbHVlKSkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiTG93IHBlcmZvcm1pbmdcbnNpbmdsZSBpbmZlY3Rpb24gY3VlcyIsIGZpbGwgPSAiQ29udmVyc2lvbiByYXRlIikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKGxpbWl0cyA9IGMoMCwgMSkpICsKICB4bGltKDEsIDIwKSArCiAgdGhlbWVfYncoKQoKIyBwbG90IGhpZ2ggcGVyZm9tcmluZwpzaV9jci5wbDIgPC0gZ2dwbG90KCkgKwogIGdlb21fdGlsZShkYXRhID0gc2lfY3IuaGlnaCwgYWVzKHggPSB0aW1lLCB5ID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoZXpfbGFiZWxfc2ksIGZpdG5lc3Nfc2kpLCBmaWxsID0gdmFsdWUpKSArCiAgbGFicyh4ID0gIiIsIHkgPSAiSGlnaCBwZXJmb3JtaW5nXG5zaW5nbGUgaW5mZWN0aW9uIGN1ZXMiLCBmaWxsID0gIkNvbnZlcnNpb24gcmF0ZSIpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDAsIDEpKSArCiAgeGxpbSgxLCAyMCkgKwogIHRoZW1lX2J3KCkKYGBgCgojIHNhdmUgZmlndXJlIGZvciBwb3N0ZXIKYGBge3J9CmdnYXJyYW5nZShzaV9jci5wbDIsIHNpX2NyLnBsMSwgY29tbW9uLmxlZ2VuZCA9IFQsIG5jb2wgPSAxLCBucm93ID0gMikKZ2dzYXZlKGhlcmUoInBvc3Rlci90aW1lX3Nlcmllc19jdi5wbmciKSwgd2lkdGggPSA3LCBoZWlnaHQgPSA0KQpgYGAKCgojIGNvLWluZmVjdGlvbiBjb252ZXJzaW9uIHJhdGUgaGVhdG1hcAojIHBsb3QgY28taW5mZWNpdG9uIGNvbnZlc2lvbiByYXRlIGhlYXRtYXAKYGBge3J9CiMgZ2V0IGZpbnRlc3MKY2lfY3IuZGYgPC0gY2lfZHluLmRmICU+JSAKICBmaWx0ZXIodGltZSA8PSAyMCAmIHZhcmlhYmxlID09ICJjcl8xIikKCiMgZ29vZCBjdWUgYmFkIGN1ZQpjaV9jdWUuZHYgPC0gY2lfZml0bmVzcy5kZiAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gY2FzZV93aGVuKAogICAgdmFsdWUgPiAyLjI1IH4gIkhpZ2gtcGVyZm9ybWluZyIsCiAgICB2YWx1ZSA8PSAyLjI1IH4gIlBvb3ItcGVyZm9ybWluZyIKICApKQoKIyBqb2luIHdpdGggY2xhc3NpZmljYWl0b24KY2lfY3IuZGYyIDwtIGNpX2NyLmRmICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGNpX2N1ZS5kdiwgbGFiZWwsIGNsYXNzaWZpY2F0aW9uLCBmaXRuZXNzX2NpID0gdmFsdWUpLCBieSA9ICJsYWJlbCIpICU+JSAKICBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gYygibGFiZWwiID0gImxhYmVsX2NpIikpCgojIHNwbGl0IGludG8gdG9wIGVyZm9ybWluZyBhbmQgcG9vci1wZXJmb3JtaW5nIGN1ZXMKY2lfY3IuaGlnaCA8LSBjaV9jci5kZjIgJT4lIGZpbHRlcihjbGFzc2lmaWNhdGlvbiA9PSAiSGlnaC1wZXJmb3JtaW5nIikKY2lfY3IucG9vciA8LSBjaV9jci5kZjIgJT4lIGZpbHRlcihjbGFzc2lmaWNhdGlvbiA9PSAiUG9vci1wZXJmb3JtaW5nIikKYGBgCgojIHBsb3QKYGBge3J9CiMgcGxvdCBwb29yIHBlcmZvcm1pbmcKY2lfY3IucGwxIDwtIGdncGxvdCgpICsKICBnZW9tX3RpbGUoZGF0YSA9IGNpX2NyLnBvb3IsIGFlcyh4ID0gdGltZSwgeSA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGV6X2xhYmVsX3NpLCBmaXRuZXNzX2NpKSwgZmlsbCA9IHZhbHVlKSkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiTG93IHBlcmZvcm1pbmdcbmNvLWluZmVjdGlvbiBjdWVzIiwgZmlsbCA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MobGltaXRzID0gYygwLCAxKSkgKwogIHhsaW0oMSwgMjApICsKICB0aGVtZV9idygpCgojIHBsb3QgaGlnaCBwZXJmb21yaW5nCmNpX2NyLnBsMiA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV90aWxlKGRhdGEgPSBjaV9jci5oaWdoLCBhZXMoeCA9IHRpbWUsIHkgPSBmb3JjYXRzOjpmY3RfcmVvcmRlcihlel9sYWJlbF9zaSwgZml0bmVzc19jaSksIGZpbGwgPSB2YWx1ZSkpICsKICBsYWJzKHggPSAiIiwgeSA9ICJIaWdoIHBlcmZvcm1pbmdcbmNvLWluZmVjdGlvbiBjdWVzIiwgZmlsbCA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MobGltaXRzID0gYygwLCAxKSkgKwogIHhsaW0oMSwgMjApICsKICB0aGVtZV9idygpCmBgYAoKIy0tLS0tLS0tLSBhc3NlbWJsZSBmaW5hbCBmaWd1cmUgLS0tLS0tLS0tLS0tLS0jCmBgYHtyfQojIGFzc2VtYmxlIHRoZSBjciBwbG90cyBmaXJzdApvcHRfY3VlX3BsLkMgPC0gZ2dhcnJhbmdlKHNpX2NyLnBsMiwgY2lfY3IucGwyLCBzaV9jci5wbDEsIGNpX2NyLnBsMSwgbmNvbCA9IDIsIG5yb3cgPSAyLCBjb21tb24ubGVnZW5kID0gVCwgYWxpZ24gPSAiaHYiKQoKIyBhc3NlbWJsZSBwYW5lbCBCIGFuZCBDCm9wdF9jdWVfcGwuQkMgPC0gZ2dhcnJhbmdlKG9wdF9jdWVfcGwuQiwgb3B0X2N1ZV9wbC5DLCBuY29sID0gMSwgbnJvdyA9IDIsIGxhYmVscyA9IGMoIkIiLCAiQyIpLCBoZWlnaHRzID0gYygwLjc1LCAxKSkKCiMgYXNzZW1ibGUgZmluYWwgZmlndXJlCmdnYXJyYW5nZShvcHRfY3VlX3BsLkEsIG9wdF9jdWVfcGwuQkMsIG5jb2wgPSAyLCBucm93ID0gMSwgbGFiZWxzID0gYygiQSIsICIiKSwgd2lkdGhzID0gYygwLjc1LCAxKSkKCiMgc2F2ZSBmaWd1cmUKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vb3B0X2N1ZS50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMjUwLCBoZWlnaHQgPSAxNTAwLCBzY2FsZSA9IDIsIGRwaT0zMDAsIGNvbXByZXNzaW9uID0gImx6dyIpCmBgYAoKIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwojIGR1YWwgY3VlIG9wdGltaXphdGlvbiBmaWd1cmUKIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwpgYGB7cn0Kc291cmNlKGhlcmUoImZ1bmN0aW9ucy9jaGFiYXVkaV9zaV9jbGVhbl9oaWdoLlIiKSkKc291cmNlKGhlcmUoImZ1bmN0aW9ucy9jaGFiYXVkaV9zaV9jbGVhbi5SIikpCnNvdXJjZShoZXJlKCJmdW5jdGlvbnMvcGFyX3RvX2htX3RlLlIiKSkKYGBgCgojLS0tLS0tLS0tLSBwbG90dGluZyBmaXRuZXNzIG9mIGR1YWwgdnMgc2luZ2xlIGN1ZSBvcHQgLS0tLS0tLS0tIwojIGltcG9ydCBpbiBwcmV2aW91cyBkYXRhCmBgYHtyfQojIGR1YWwgY3VlIGZpdG5lc3MKZHVhbF9maXRuZXNzLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvZHVhbF9jdWVfb3B0NC9kdWFsX2N1ZV9maXRuZXNzXzIwLmNzdiIpKQojIyBtYWtlIGxhYmVsIGFuZCBmaWx0ZXIgb3V0IHZlcnkgbG93IGZpdG5lc3MKZHVhbF9maXRuZXNzLmRmIDwtIGR1YWxfZml0bmVzcy5kZiAlPiUgCiAgbXV0YXRlKHRlbXBfbGFiZWwgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBsYWJlbCksCiAgICAgICAgIHRlbXBfbGFiZWxfYiA9IGdzdWIoImxvZyIsICJsb2cxMCIsIGxhYmVsX2IpLAogICAgICAgICBsYWJlbF9maW5hbCA9IHBhc3RlMCh0ZW1wX2xhYmVsLCAiKyIsIHRlbXBfbGFiZWxfYikpICU+JSAKICBmaWx0ZXIodmFsdWUgPiAyKQoKIyBnZXQgc2luZ2xlIGN1ZSBmaXRuZXNzCnNpX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9zaV9keW4vc2lfZHluXzMwLnBhcnF1ZXQiKSkgCnNpX2ZpdG5lc3MuZGYgPC0gc2lfZHluLmRmICU+JSAKICBmaWx0ZXIodmFyaWFibGUgPT0gInRhdV9jdW0iICYgdGltZSA9PSAyMCkKCiMgam9pbiBzaSBhbmQgZHVhbCBjdWUKZHVhbF9zaV9maXRuZXNzLmRmIDwtIGR1YWxfZml0bmVzcy5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChzaV9maXRuZXNzLmRmLCBpZCwgc2lfZml0bmVzcyA9IHZhbHVlKSwgYnkgPSAiaWQiKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChzaV9maXRuZXNzLmRmLCBpZF9iID0gaWQsIHNpX2ZpdG5lc3NfYiA9IHZhbHVlKSwgYnkgPSAiaWRfYiIpICU+JSAKICBtdXRhdGUoc2lfZml0bmVzc19tYXggPSBpZmVsc2Uoc2lfZml0bmVzcyA+IHNpX2ZpdG5lc3NfYiwgc2lfZml0bmVzcywgc2lfZml0bmVzc19iKSwKICAgICAgICAgZHVhbF9sYWJlbCA9IGdzdWIoImxvZyIsICJsb2cxMCIsIHBhc3RlKGxhYmVsLCAiKyIsIGxhYmVsX2IpKSkKYGBgCgojIHBsb3QKYGBge3J9CmR1YWxfc2lfZml0bmVzcy5wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbF9zaV9maXRuZXNzLmRmLCBhZXMoeSA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGR1YWxfbGFiZWwsIHZhbHVlKSwgeCA9IHZhbHVlLCBjb2xvciA9ICJEdWFsIGN1ZSIpLCBzaXplID0gMi41LCBhbHBoYSA9IDAuNykgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1YWxfc2lfZml0bmVzcy5kZiwgYWVzKHkgPSBmb3JjYXRzOjpmY3RfcmVvcmRlcihkdWFsX2xhYmVsLCB2YWx1ZSksIHggPSBzaV9maXRuZXNzX21heCwgY29sb3I9ICJCZXN0IHNpbmdsZSBjdWUiKSwgc2l6ZSA9IDIuNSwgYWxwaGEgPSAwLjcpICsKICBsYWJzKHggPSAiRml0bmVzcyIsIHkgPSAiRHVhbCBjdWUiLCBjb2xvciA9ICJDdWUiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjZmM4ZDU5IiwgIiM0NTc1YjQiKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDkuODgzNjAyKSArCiAgZ2VvbV90ZXh0KGFlcyh4PTkuODgzNjAyLCBsYWJlbD0iXG5NYXhpbXVtIGZpdG5lc3MiLCB5ID0gIkcgKyBSIGxvZzEwIiksIGFuZ2xlPTkwKSArCiAgdGhlbWVfYncoKQpgYGAKCgojLS0tLS0tLS0tLS0gdGltZSBzZXJpZXMgY29udmVyc2lvbiByYXRlIC0tLS0tLS0tLS0tLS0jCiMgZHluYW1pY3Mgc2ltdWxhdGlvbiBvZiBoaWdoIHBhcmFtZXRlciBjdWVzICh0aGVzZSBzZXJ2ZSBhcyByZWZlcmVuY2UgcG9pbnRzKQpgYGB7cn0KIyBiZXN0IGR1YWwgY3VlIGNvbWJvCmR1YWwuY3IgPC0gY2hhYmF1ZGlfc2lfY2xlYW4oCiAgcGFyYW1ldGVyc19jciA9IGMoNC40NDYxOTIwMzMsCTEwLjk3NTE4Mjc1LAkxLjM4NzYyODE3LAkyMy4zMDU5MjU0LAktMy40NTIwNTIzNzEsCS0xOC4wMDcwNjkyLAkzOS42NjYxNDIyNiwJLTMuNTQ1MTkzMTQxLAkxOC43ODM1MDc5OSksCiAgaW1tdW5pdHkgPSAidHN1a3VzaGkiLAogIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogIHRpbWVfcmFuZ2UgPSBzZXEoMCwgMjAsIGJ5ID0gMWUtMyksCiAgY3VlX3JhbmdlID0gIHNlcSg2LCA3LCBieSA9IDEvNTAwKSwKICBjdWVfcmFuZ2VfYiA9IHNlcSgwLCBsb2cxMCg2KigxMF42KSksIGJ5ID0gKGxvZzEwKDYqKDEwXjYpKSkvNTAwKSwKICBjdWUgPSAiUiIsCiAgY3VlX2IgPSAiSSIsCiAgbG9nX2N1ZSA9ICJsb2cxMCIsCiAgbG9nX2N1ZV9iID0gImxvZzEwIiwKICBzb2x2ZXIgPSAidm9kZSIsCiAgZHluID0gVAopCgojIHdoZW4gdGltZSBpcyB1c2VkIGFzIGEgY3VlIChoaWdoIHBhcmFtZXRlcikKdGltZS5jciA8LSBjaGFiYXVkaV9zaV9jbGVhbl9oaWdoKAogIHBhcmFtZXRlcnNfY3IgPSBjKDkuMTU0MzE0LCAgLTcuNTcwODI5LCAtMjIuNTA2NjM4ICwgIDMuMzgyNDA1ICwtMTMuNDUzNTE5ICwtMTcuMDExNDg1ICAsIDMuNjc4MTgxLCAtMTIuODUxODk1ICwtMjYuMTE1MTU4KSwKICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgdGltZV9yYW5nZSA9IHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICBjdWVfcmFuZ2UgPSAgc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogIGN1ZSA9ICJ0IiwKICBzb2x2ZXIgPSAidm9kZSIsCiAgZHluID0gVCkKCiMgd2hlbiBhc2V4dWFsIGlSQkMgaXMgdXNlZCBhcyBhIGN1ZSAoaGlnaCBmbGV4aWJpbGl0eSkKSV9oaWdoLmNyIDwtIGNoYWJhdWRpX3NpX2NsZWFuX2hpZ2goCiAgcGFyYW1ldGVyc19jciA9IGMoMS4yOTY2NzUsICAzLjU0NDAzNCAsIDQuOTA3NDg0LCAgMi4xNzQyNDksIC0zLjIzODMwOSAsLTUuMTgxNjE0ICwtMS42NDUwNzIgLCAxLjgzNDMwMiAsIDEuNTgxMDExKSwKICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgdGltZV9yYW5nZSA9IHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICBjdWVfcmFuZ2UgPSAgc2VxKDAsIGxvZzEwKDYqKDEwXjYpKSwgYnkgPSAobG9nMTAoNiooMTBeNikpKS81MDAwKSwKICBjdWUgPSAiSSIsCiAgbG9nX2N1ZSA9ICJsb2cxMCIsCiAgc29sdmVyID0gInZvZGUiLAogIGR5biA9IFQpCgojIHdoZW4gYXNleHVhbCBpUkJDIGlzIHVzZWQgYXMgYSBjdWUgKG5vcm1hbCBmbGV4aWJpbGl0eSkKSS5jciA8LSBjaGFiYXVkaV9zaV9jbGVhbigKICBwYXJhbWV0ZXJzX2NyID0gYyg1LjQ2MzU1OCwJMi4zODM5NDgsCS0xNy43NTcyODEsCTQuNTcxODM1KSwKICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgdGltZV9yYW5nZSA9IHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICBjdWVfcmFuZ2UgPSAgc2VxKDAsIGxvZzEwKDYqKDEwXjYpKSwgYnkgPSAobG9nMTAoNiooMTBeNikpKS81MDAwKSwKICBjdWUgPSAiSSIsCiAgbG9nX2N1ZSA9ICJsb2cxMCIsCiAgc29sdmVyID0gInZvZGUiLAogIGR5biA9IFQpCgojIHByb2Nlc3MgCklfaGlnaC5jcjIgPC0gSV9oaWdoLmNyICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gImNyIikgJT4lIG11dGF0ZShsYWJlbF9uZXcgPSAiSSBsb2cxMCBmbGV4aWJsZSIpICU+JSBzZWxlY3QoLXZhcmlhYmxlKQoKSS5jcjIgPC0gSS5jciAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpICU+JSBtdXRhdGUobGFiZWxfbmV3ID0gIkkgbG9nMTAiKSAlPiUgc2VsZWN0KC12YXJpYWJsZSkKCnRpbWVfaGlnaC5jcjIgPC0gdGltZS5jciAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpICU+JSBtdXRhdGUobGFiZWxfbmV3ID0gIlRpbWUgZmxleGlibGUiKSAlPiUgc2VsZWN0KC12YXJpYWJsZSkKCmR1YWwuY3IyIDwtIGR1YWwuY3IgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiY3IiKSAlPiUgbXV0YXRlKGxhYmVsX25ldyA9ICJSIGxvZzEwICsgSSBsb2cxMCIpICU+JSBzZWxlY3QoLXZhcmlhYmxlKQoKIyBjb21iaW5lCmR1YWxfY3IuZGYgPC0gcmJpbmQoSV9oaWdoLmNyMiwgSS5jcjIsIHRpbWVfaGlnaC5jcjIsIGR1YWwuY3IyKQpgYGAKCiMgcGxvdApgYGB7cn0KZHVhbF9jci5wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsX2NyLmRmLCBhZXMoY29sb3IgPSBsYWJlbF9uZXcsIHggPSB0aW1lLCB5ID0gdmFsdWUpLCBzaXplID0gMSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1YWxfY3IuZGYgJT4lIGZpbHRlcih0aW1lJSUxID09IDApLCBhZXMoY29sb3IgPSBsYWJlbF9uZXcsIHggPSB0aW1lLCB5ID0gdmFsdWUsIHNoYXBlID0gbGFiZWxfbmV3KSwgc2l6ZSA9IDIpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiLCB5ID0gIkNvbnZlcnNpb24gcmF0ZSIsIGNvbG9yID0gIkN1ZSIsIHNoYXBlID0gIkN1ZSIpICsKICB4bGltKDAsIDIwKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiM0NTc1YjQiLCAiIzkxYmZkYiIsIiNmYzhkNTkiLCIjZmRjYjQ0IikpICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDIsIGJ5cm93ID0gVFJVRSkpCmBgYAoKIy0tLS0tLS0tLS0tLSByZWFjdGlvbiBub3JtIGhlYXRtYXAgb2YgUiBsb2cxMCArIEkgbG9nMTAgLS0tLS0tLS0tLS0tIwojIHByb2Nlc3MgZGF0YQpgYGB7cn0KIyBtYWtlIGhlYXRtYXAgZGYKUl9JLmhtIDwtIHBhcl90b19obV90ZShwYXIgPSBjKDQuNDQ2MTkyMDMzLAkxMC45NzUxODI3NSwJMS4zODc2MjgxNywJMjMuMzA1OTI1NCwJLTMuNDUyMDUyMzcxLAktMTguMDA3MDY5MiwJMzkuNjY2MTQyMjYsCS0zLjU0NTE5MzE0MSwJMTguNzgzNTA3OTkpLAogICAgICAgICAgICAgY3VlX3JhbmdlID0gc2VxKDYsCTcsIGxlbmd0aC5vdXQgPSA1MDApLAogICAgICAgICAgICAgY3VlX3JhbmdlX2IgPSBzZXEoMCwJNi43NzgxNTEyNSwgbGVuZ3RoLm91dCA9IDUwMCkpCgojIHByb2Nlc3MgZHluYW1pY3MKUl9JLmR5biA8LSBkdWFsLmNyICU+JSAKICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHZhcmlhYmxlLCB2YWx1ZXNfZnJvbSA9IHZhbHVlKSAlPiUgCiAgbXV0YXRlKGxvZ19SID0gbG9nMTAoUiksCiAgICAgICAgIGxvZ19JID0gbG9nMTAoSSkpCmBgYAoKIyBwbG90CmBgYHtyfQpkdWFsX3JuLnBsIDwtIGdncGxvdCgpICsKICBnZW9tX3Jhc3RlcihkYXRhID0gUl9JLmhtLCBhZXMoeCA9IGN1ZV9yYW5nZV9iLCB5ID0gY3VlX3JhbmdlLCBmaWxsID0gY3IpKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBSX0kuZHluLCBhZXMoeCA9IGxvZ19JLCB5ID0gbG9nX1IpLCBjb2xvciA9ICJ3aGl0ZSIsIGFycm93ID0gYXJyb3coYW5nbGUgPSAzMCwgbGVuZ3RoID0gdW5pdCgwLjEsICJpbmNoZXMiKSkpICsKICBnZW9tX3BvaW50KGRhdGEgPSBSX0kuZHluICU+JSBmaWx0ZXIocm93X251bWJlcigpICUlIDEwMDAgPT0gMSAmIHRpbWUgPD0gMjApLCBhZXMoeCA9IGxvZ19JLCB5ID0gbG9nX1IpLCBjb2xvciA9ICJ3aGl0ZSIpICsKICB4bGltKDAuOTkqbWluKGhhYmxhcjo6cyhSX0kuZHluJGxvZ19JKSwgbmEucm0gPSBUKSwgMS4wMSogbWF4KGhhYmxhcjo6cyhSX0kuZHluJGxvZ19JKSwgbmEucm0gPSBUKSkgKwogIHlsaW0oMC45OSptaW4oaGFibGFyOjpzKFJfSS5keW4kbG9nX1IpLCBuYS5ybSA9IFQpLDEuMDEqIG1heChoYWJsYXI6OnMoUl9JLmR5biRsb2dfUiksIG5hLnJtID0gVCkpICsKICBsYWJzKHkgPSAiUkJDIGxvZzEwIiwgeCA9ICJBc2V4dWFsIGlSQkMgbG9nMTAiLCBmaWxsID0gIkNvbnZlcnNpb24gcmF0ZSIpICsKICB0aGVtZV9kYXJrKCkKYGBgCgojIHNhdmUgZmlndXJlIGZvciBwb3N0ZXIKYGBge3J9CmR1YWxfcm4ucGwyIDwtIGdncGxvdCgpICsKICBnZW9tX3Jhc3RlcihkYXRhID0gUl9JLmhtLCBhZXMoeCA9IGN1ZV9yYW5nZV9iLCB5ID0gY3VlX3JhbmdlLCBmaWxsID0gY3IpKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBSX0kuZHluLCBhZXMoeCA9IGxvZ19JLCB5ID0gbG9nX1IpLCBjb2xvciA9ICJ3aGl0ZSIsIGFycm93ID0gYXJyb3coYW5nbGUgPSAzMCwgbGVuZ3RoID0gdW5pdCgwLjEsICJpbmNoZXMiKSkpICsKICBnZW9tX3BvaW50KGRhdGEgPSBSX0kuZHluICU+JSBmaWx0ZXIocm93X251bWJlcigpICUlIDEwMDAgPT0gMSAmIHRpbWUgPD0gMjApLCBhZXMoeCA9IGxvZ19JLCB5ID0gbG9nX1IpLCBjb2xvciA9ICJ3aGl0ZSIpICsKICB4bGltKDAuOTkqbWluKGhhYmxhcjo6cyhSX0kuZHluJGxvZ19JKSwgbmEucm0gPSBUKSwgMS4wMSogbWF4KGhhYmxhcjo6cyhSX0kuZHluJGxvZ19JKSwgbmEucm0gPSBUKSkgKwogIHlsaW0oMC45OSptaW4oaGFibGFyOjpzKFJfSS5keW4kbG9nX1IpLCBuYS5ybSA9IFQpLDEuMDEqIG1heChoYWJsYXI6OnMoUl9JLmR5biRsb2dfUiksIG5hLnJtID0gVCkpICsKICBsYWJzKHkgPSAiUkJDIGxvZzEwIiwgeCA9ICJBc2V4dWFsIGlSQkMgbG9nMTAiLCBmaWxsID0gIkNvbnZlcnNpb24gcmF0ZSIpICsKICB0aGVtZV9kYXJrKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb249InRvcCIpIAoKZHVhbF9jci5wbDIgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZHVhbF9jci5kZiwgYWVzKGNvbG9yID0gbGFiZWxfbmV3LCB4ID0gdGltZSwgeSA9IHZhbHVlKSwgc2l6ZSA9IDEpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX2NyLmRmICU+JSBmaWx0ZXIodGltZSUlMSA9PSAwKSwgYWVzKGNvbG9yID0gbGFiZWxfbmV3LCB4ID0gdGltZSwgeSA9IHZhbHVlLCBzaGFwZSA9IGxhYmVsX25ldyksIHNpemUgPSAyKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJDb252ZXJzaW9uIHJhdGUiLCBjb2xvciA9ICJDdWUiLCBzaGFwZSA9ICJDdWUiKSArCiAgeGxpbSgwLCAyMCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjNDU3NWI0IiwgIiM5MWJmZGIiLCIjZmM4ZDU5IiwiI2ZkY2I0NCIpKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAyLCBieXJvdyA9IFRSVUUpKQoKZ2dhcnJhbmdlKGR1YWxfY3IucGwyLCBkdWFsX3JuLnBsMiwgYWxpZ24gPSAiaCIsIHdpZHRocyA9IGMoMS4yNSwgMSkpCmdnc2F2ZShoZXJlKCJwb3N0ZXIvZHVhbF9jdWUucG5nIiksIHdpZHRoID0gNywgaGVpZ2h0ID0gNCkKYGBgCgoKIy0tLS0tLS0tIGFzc2VtYmxlIGZpbmFsIGZpZ3VyZSAtLS0tLS0tLS0tLS0tIwpgYGB7cn0KIyBhc3NlbWJsZSBwYW5lbCBCIGFuZCBDCmR1YWxfcGwuQkMgPC0gZ2dhcnJhbmdlKGR1YWxfY3IucGwsIGR1YWxfcm4ucGwsIGFsaWduID0gInYiLCBuY29sID0gMSwgbGFiZWxzID0gYygiQiIsICJDIikpCgojIGFzc2VtYmxlIHBhbmVsIEEKZHVhbC5wbCA8LSBnZ2FycmFuZ2UoZHVhbF9zaV9maXRuZXNzLnBsLCBkdWFsX3BsLkJDLCBuY29sID0gMiwgbGFiZWxzID0gYygiQSIsICIiKSwgd2lkdGhzID0gYygxLCAwLjc1KSkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vZHVhbF9jdWUudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjI1MCwgaGVpZ2h0ID0gMTQwMCwgc2NhbGUgPSAxLjUsIGRwaT0zMDAsIGNvbXByZXNzaW9uID0gImx6dyIpCmBgYAoKIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCiMgaGV0ZXJvY3VlIGFkb3B0aW9uIAojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSMKCiMtLS0tLS0tIHN0YXRpYyBjb21wZXRpdGlvbiAtLS0tLS0tLS0tLS0tLS0jCiMgY2FsY3VsYXRlIGZpdG5lc3MgZGlmZmVyZW5jZSBmb3IgMjAgZGF5cwpgYGB7cn0KIyBnZXQgZHluYW1pY3MKc3RhdGljLmxzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvY2lfc3RhdGljLyIpLCBwYXR0ZXJuID0gIioucGFycXVldCIsIGZ1bGwubmFtZXMgPSBUKQpzdGF0aWMubHMgPC0gbGFwcGx5KHN0YXRpYy5scywgcmVhZF9wYXJxdWV0KQoKIyBnZXQgZml0bmVzcyBhdCBkYXkgMjAgKG9wdGltaXplZCBmb3IgMjAgZGF5cykKc3RhdGljX2ZpdG5lc3MubHMgPC0gbWNsYXBwbHkoc3RhdGljLmxzLCBmdW5jdGlvbih4KXsKICB4ICU+JSBmaWx0ZXIodGltZSA9PSAyMCAmIHZhcmlhYmxlICVpbiUgYygidGF1X2N1bTEiLCAidGF1X2N1bTIiKSkKfSkKc3RhdGljX2ZpdG5lc3MuZGYgPC0gZG8uY2FsbChyYmluZCwgc3RhdGljX2ZpdG5lc3MubHMpCgpzdGF0aWNfZml0bmVzcy5kZiA8LSB0aWR5cjo6cGl2b3Rfd2lkZXIoc3RhdGljX2ZpdG5lc3MuZGYsIG5hbWVzX2Zyb20gPSAidmFyaWFibGUiLCBpZF9jb2xzID0gYygiaWRfMSIsICJpZF8yIikpICU+JSAKICBncm91cF9ieShpZF8xLCBpZF8yKSAlPiUgCiAgbXV0YXRlKGZpdG5lc3NfZGlmZmVyZW5jZSA9IHRhdV9jdW0xLXRhdV9jdW0yKQp3cml0ZS5jc3Yoc3RhdGljX2ZpdG5lc3MuZGYsIGhlcmUoImRhdGEvY2lfc3RhdGljLmNzdiIpKQpgYGAKCiMgaW1wb3J0IGFuZCBwcm9jZXNzIGRhdGEKYGBge3J9CiMgaW1wb3J0IGluIGRhdGFzZXQKc3RhdGljLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY2lfc3RhdGljLmNzdiIpKQplel9sYWJlbCA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2V6X2xhYmVsLmNzdiIpKQoKIyBqb2luIHdpdGggbGFiZWxsaW5nCnN0YXRpYy5kZjIgPC0gc3RhdGljLmRmICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgbGFiZWxfY2lfMSA9IGxhYmVsX2NpKSwgYnkgPSBjKCJpZF8xIiA9ICJpZF9jaSIpKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfY2ksIGxhYmVsX2NpXzIgPSBsYWJlbF9jaSksIGJ5ID0gYygiaWRfMiIgPSAiaWRfY2kiKSkgJT4lIAogIHNlbGVjdChsYWJlbF9jaV8xLCBsYWJlbF9jaV8yLCBmaXRuZXNzX2RpZmZlcmVuY2UpICU+JSAKICBtdXRhdGUobGFiZWxfY2lfMSA9IGdzdWIoImxvZyIsICJsb2cxMCIsIGxhYmVsX2NpXzEpLAogICAgICAgICBsYWJlbF9jaV8yID0gZ3N1YigibG9nIiwgImxvZzEwIiwgbGFiZWxfY2lfMikpCgojIGdldCByZXZlcnNlIG9yZGVyLCB3aGljaCBpcyBzaW1wbHkgaW52b3ZsZXMgc3dpdGNoaW5nIHRoZSBjdWVzIGFyb3VuZCB0aGUgbXVsdGlwbHlpbmcgdGhlIGZpdG5lc3MgYnkgbmVnYXRpdmUgMQpzdGF0aWMuZGYzIDwtIHN0YXRpYy5kZjIKbmFtZXMoc3RhdGljLmRmMykgPC0gYygibGFiZWxfY2lfMiIsICJsYWJlbF9jaV8xIiwgImZpdG5lc3NfZGlmZmVyZW5jZSIpCnN0YXRpYy5kZjMkZml0bmVzc19kaWZmZXJlbmNlIDwtIHN0YXRpYy5kZjIkZml0bmVzc19kaWZmZXJlbmNlICogLTEKCiMgam9pbgpzdGF0aWMuZGY0IDwtIHJiaW5kKHN0YXRpYy5kZjIsIHN0YXRpYy5kZjMpCiMgZ2V0IG1lYW4Kc3RhdGljLm1lYW4gPC0gc3RhdGljLmRmNCAlPiUgCiAgZ3JvdXBfYnkobGFiZWxfY2lfMSkgJT4lIAogIHN1bW1hcml6ZShtZWFuX2ZpdG5lc3MgPSBtZWFuKGZpdG5lc3NfZGlmZmVyZW5jZSwgbmEucm0gPSBUKSkKYGBgCgojIHBsb3QKYGBge3J9CiMgaGVhdG1hcApzdGF0aWMucGwxIDwtIGdncGxvdChkYXRhID0gc3RhdGljLmRmNCwgYWVzKHggPSBsYWJlbF9jaV8yLCB5ID0gbGFiZWxfY2lfMSwgZmlsbCA9IGZpdG5lc3NfZGlmZmVyZW5jZSkpKwogIGdlb21fdGlsZShjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiI2ZjOGQ1OSIsIGhpZ2ggPSAiIzQ1NzViNCIsIG1pZCA9ICJ3aGl0ZSIsIAogICBtaWRwb2ludCA9IDAsIHNwYWNlID0gIkxhYiIsIGxpbSA9IGMoLTAuOTUsIDAuOTUpLCBuYW1lPSJGaXRuZXNzXG5kaWZmZXJlbmNlIikgKwogIHRoZW1lX21pbmltYWwoKSArICAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibGVmdCIsCiAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAxLCBoanVzdCA9IDEpLAogIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgcGxvdC5tYXJnaW49bWFyZ2luKHIgPSAwKSkgKyAKICBsYWJzKHggPSAiU3RyYWluIDIgY3VlIiwgeSA9ICJTdHJhaW4gMSBjdWUiKSArCiAgY29vcmRfZml4ZWQoKQoKIyBtZWFuIApzdGF0aWMucGwyIDwtIGdncGxvdCgpICsKICBnZW9tX2JhcihkYXRhID0gIHN0YXRpYy5tZWFuLCBhZXMoeSA9IGxhYmVsX2NpXzEsIHggPSBtZWFuX2ZpdG5lc3MpLCBzdGF0ID0gImlkZW50aXR5IikgKwogIGxhYnMoeSA9ICIiLCB4ID0gIk1lYW4gZml0bmVzc1xuZGlmZmVyZW5jZSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwbG90Lm1hcmdpbiA9IG1hcmdpbihsID0gMCksCiAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSkKCnN0YXRpYy5wbCA8LSBnZ2FycmFuZ2Uoc3RhdGljLnBsMSwgc3RhdGljLnBsMiwgYWxpZ24gPSAiaHYiLCB3aWR0aHMgPSBjKDEsIDAuMikpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL3N0YXRpY19oZWF0bWFwLnRpZmYiKSwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNikKYGBgCgojLS0tLS0tIGludmFzaW9uIG1hdHJpeCAtLS0tLS0tLS0tLS0tLS0tLS0tLSMKIyBpbXBvcnQgaW4gZGF0YSAoYWxyZWFkeSAyMCBkYXlzICkKYGBge3J9CmludmFkZS5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX2ludmFzaW9uLmNzdiIpKQpgYGAKCgojIHByb2Nlc3MgZGF0YSBmb3IgaW52YXNpb24gbWF0cml4CmBgYHtyfQppbnZhZGUubWF0IDwtIGludmFkZS5kZiAlPiUgCiAgZ3JvdXBfYnkoVjEgPSBwbWluKG11dF9pZCwgcmVzX2lkKSwgVjIgPSBwbWF4KG11dF9pZCwgcmVzX2lkKSkgJT4lICMgZ3JvdXAgYnkgY3VlIGNvbXBldGl0aW9uLCBpcnJlZ2FyZGxlc3Mgb2Ygb3JkZXIKICBtdXRhdGUoaWRfYWx0ID0gcGFzdGUwKFYxLCBWMiksCiAgICAgICAgIGludmFkZSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBmaXRuZXNzID4gMCB+ICJpbnZhZGUiLAogICAgICAgICAgIGZpdG5lc3MgPCAwIH4gIm5vdCBpbnZhZGUiCiAgICAgICAgICkpICU+JSAKICBncm91cF9ieShpZF9hbHQpICU+JSAKICBtdXRhdGUoCiAgICBtdXRfaXNfVjEgPSBjYXNlX3doZW4oCiAgICBtdXRfaWQgPT0gVjEgfiAiVjFfaW52YWRlIiwKICAgIG11dF9pZCAhPSBWMSB+ICJWMV9pbnZhZGVkIikpICU+JSAKICBhcnJhbmdlKGlkX2FsdCkgJT4lIAogIHNlbGVjdChmaXRuZXNzLCBWMSwgVjIsIGlkX2FsdCwgaW52YWRlLCBtdXRfaXNfVjEpICU+JSAKICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IG11dF9pc19WMSwgdmFsdWVzX2Zyb20gPSBmaXRuZXNzKSAlPiUgCiAgZ3JvdXBfYnkoaWRfYWx0KSAlPiUgCiAgbXV0YXRlKFYxX2ludmFkZTIgPSBnc3ViKCJOQSIsICIiLCBwYXN0ZTAoVjFfaW52YWRlLCBjb2xsYXBzZSA9ICIiKSksCiAgICAgICAgIFYxX2ludmFkZWQyID0gZ3N1YigiTkEiLCAiIiwgcGFzdGUwKFYxX2ludmFkZWQsIGNvbGxhcHNlID0gIiIpKSkgJT4lIAogIGRpc3RpbmN0KGlkX2FsdCwgLmtlZXBfYWxsID0gVCkgJT4lIAogIG11dGF0ZSgKICAgIGNhdGVnb3J5ID0gY2FzZV93aGVuKAogICAgVjFfaW52YWRlMiA+IDAgJiBWMV9pbnZhZGVkMiA+IDAgfiAiTXV0dWFsIGludmFzaW9uIiwKICAgIFYxX2ludmFkZTIgPiAwICYgVjFfaW52YWRlZDIgPCAwIH4gIk9ubHkgc3RyYWluIDEgaW52YXNpb24iLAogICAgVjFfaW52YWRlMiA8IDAgJiBWMV9pbnZhZGVkMiA+IDAgfiAiT25seSBzdHJhaW4gMiBpbnZhc2lvbiIsCiAgICBWMV9pbnZhZGUyIDwgMCAmIFYxX2ludmFkZWQyIDwgMCB+ICJNdXR1YWwgbm9uLWludmFzaW9uIgogICkpICU+JSAKICBzZWxlY3QoVjEsIFYyLCBpbnZhc2lvbiA9IGNhdGVnb3J5KQoKIyBmb3IgcGxvdHRpbmcsIG5lZWQgdG8gZ2V0IGFsbCBzYW1lIGN1ZSB2cyBzYW1lIGN1ZSwgd2hpY2ggd2Ugd2lsbCBzZXQgdG8gTkEKaW52YWRlLk5BIDwtIGNiaW5kLmRhdGEuZnJhbWUoYFYxYCA9IHVuaXF1ZShpbnZhZGUubWF0JFYxKSwKICAgICAgYFYyYCA9IHVuaXF1ZShpbnZhZGUubWF0JFYxKSwKICAgICAgaW52YXNpb24gPSBOQSkKCmludmFkZS5tYXQyIDwtIHJiaW5kKGludmFkZS5tYXQsIGludmFkZS5OQSkKCiMgZ2V0IGxhYmVsCmludmFkZS5tYXQzIDwtIGludmFkZS5tYXQyICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgVjFfbGFiZWwgPSBsYWJlbF9jaSksIGJ5ID0gYygiVjEiID0gImlkX2NpIikpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgVjJfbGFiZWwgPSBsYWJlbF9jaSksIGJ5ID0gYygiVjIiID0gImlkX2NpIikpICU+JSBtdXRhdGUoVjFfbGFiZWwgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBWMV9sYWJlbCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVjJfbGFiZWwgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBWMl9sYWJlbCkpCgojIHJlb3JkZXIgc28gdGhhdCBnZ3Bsb3QgZG8gbm90IG1lc3MgdXAKbGlicmFyeShndG9vbHMpCgpsZXZlbHMgPC0gbWl4ZWRzb3J0KHVuaXF1ZShjKGludmFkZS5tYXQzJFYxX2xhYmVsLCBpbnZhZGUubWF0MyRWMl9sYWJlbCkpKQoKaW52YWRlLm1hdDQgPC0gcmJpbmQoaW52YWRlLm1hdDMsIAogICAgICAgICAgICAgICAgICAgICAgICBpbnZhZGUubWF0MyAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVuYW1lKFYyX2xhYmVsID0gVjFfbGFiZWwsIFYxX2xhYmVsID0gVjJfbGFiZWwpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoVjFfbGFiZWwsIFYyX2xhYmVsLCBpbnZhc2lvbikpICU+JQogIG11dGF0ZShhY3Jvc3MoZW5kc193aXRoKCJsYWJlbCIpLAogICAgICAgICAgICAgICAgfmZhY3RvcigueCwgbGV2ZWxzID0gbGV2ZWxzKSkpICU+JQogIGZpbHRlcihhcy5pbnRlZ2VyKFYxX2xhYmVsKSA8IGFzLmludGVnZXIoVjJfbGFiZWwpKSAlPiUKICBtdXRhdGUoVjJfbGFiZWwgPSBmb3JjYXRzOjpmY3RfcmV2KFYyX2xhYmVsKSkKYGBgCgojIHBsb3QgaW52YXNpb24gbWF0cml4CmBgYHtyfQojIHBsb3QKaW52YXNpb24ucGwxIDwtIGdncGxvdChkYXRhID0gaW52YWRlLm1hdDQsIGFlcyh4ID0gVjJfbGFiZWwsIHkgPSBWMV9sYWJlbCwgZmlsbCA9IGludmFzaW9uKSkgKwogIGdlb21fdGlsZShjb2xvciA9ICJibGFjayIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IDEsIGhqdXN0ID0gMSksCiAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICBwbG90Lm1hcmdpbj1tYXJnaW4ociA9IDApKSArIAogIGxhYnMoZmlsbCA9ICJJbnZhc2lvbiIsIHggPSAiU3RyYWluIDIgY3VlIiwgeSA9ICJTdHJhaW4gMSBjdWUiKSArCiAgI3NjYWxlX3hfZGlzY3JldGUobGltaXRzID0gcmV2KSArCiAgc2NhbGVfeV9kaXNjcmV0ZShsaW1pdHMgPSByZXYpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJPbmx5IHN0cmFpbiAxIGludmFzaW9uIiA9ICIjNDU3NWI0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPbmx5IHN0cmFpbiAyIGludmFzaW9uIiA9ICIjZmM4ZDU5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNdXR1YWwgaW52YXNpb24iID0gIiNmZWUwOTAiKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgojIGNyZWF0ZSBzdW1tYXJ5IGJhciBjaGFydApgYGB7cn0KIyBjcmVhdGUgYSBzdGFja2VkIGJhcmNoYXJ0IGZvciBzdW1tYXJ5CiMjIGZpbHRlciBvdXQgbmEKaW52YWRlLm1hdGFsdCA8LSBpbnZhZGUubWF0MyAlPiUgbmEuZXhjbHVkZSgpCgojIGdldCBmcnF1ZW5jeSBmcm9tIGJvdGggc2lkZXMuIE5vdGUgd2hlbiBncm91cGluZyBmb3IgVjIsIGZyb20gdGhlIHBlcnNwZWN0aXZlIG9mIGN1ZSAyLCBzY2VuYXJyaW8gd2hlbiBzdHJhaW4gMiBpbnZhZGUgPSBzdHJhaW4gMSBpbnZhZGUKaW52YWRlLm1hdGFsdDEgPC0gaW52YWRlLm1hdGFsdCAlPiUgZ3JvdXBfYnkoVjFfbGFiZWwsIGludmFzaW9uKSAlPiUgCiAgc3VtbWFyaXplKGZyZXF1ZW5jeV8xID0gbigpKQoKaW52YWRlLm1hdGFsdDIgPC0gaW52YWRlLm1hdGFsdCAlPiUKICBtdXRhdGUoaW52YXNpb25fYWx0ID0gY2FzZV93aGVuKAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDEgaW52YXNpb24iIH4gIk9ubHkgc3RyYWluIDIgaW52YXNpb24iLAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDIgaW52YXNpb24iIH4gIk9ubHkgc3RyYWluIDEgaW52YXNpb24iLAogICAgaW52YXNpb24gPT0gIk11dHVhbCBpbnZhc2lvbiIgfiAiTXV0dWFsIGludmFzaW9uIiwKICAgIGludmFzaW9uID09ICJNdXR1YWwgbm9uLWludmFzaW9uIiB+ICJNdXR1YWwgbm9uLWludmFzaW9uIgogICkpICU+JSAKICBncm91cF9ieShWMl9sYWJlbCwgaW52YXNpb25fYWx0KSAlPiUgCiAgc3VtbWFyaXplKGZyZXF1ZW5jeV8yID0gbigpKSAgICAgCgojIGZ1bGwgam9pbiBhbmQgc3VtLiBoYXMgY29uZmlybWVkIGFsbCBvZiB0aGVtIGFkZCB1cCB0byAxNCAKaW52YWRlLm1hdGFsdDMgPC0gZnVsbF9qb2luKGludmFkZS5tYXRhbHQxLCBpbnZhZGUubWF0YWx0MiwgYnkgPSBjKCJWMV9sYWJlbCIgPSAiVjJfbGFiZWwiLCAiaW52YXNpb24iID0gImludmFzaW9uX2FsdCIpKQoKaW52YWRlLm1hdGFsdDNbaXMubmEoaW52YWRlLm1hdGFsdDMpXSA8LSAwCmludmFkZS5tYXRhbHQ0IDwtIGludmFkZS5tYXRhbHQzICU+JSAKICBtdXRhdGUoZnJlcSA9IGZyZXF1ZW5jeV8xICsgZnJlcXVlbmN5XzIpICU+JSAKICBtdXRhdGUodGVtcCA9IGNhc2Vfd2hlbigKICAgIGludmFzaW9uID09ICJPbmx5IHN0cmFpbiAxIGludmFzaW9uIiB+IGZyZXEKICApKSAlPiUgCiAgZ3JvdXBfYnkoVjFfbGFiZWwpICU+JSAKICBtdXRhdGUoaW52YWRlXzFfZnJlcSA9IG1heCh0ZW1wLCBuYS5ybSA9IFQpKQogIAppbnZhc2lvbi5wbDIgPC0gZ2dwbG90KCkgKwogIGdlb21fYmFyKGRhdGEgPSBpbnZhZGUubWF0YWx0NCwgYWVzKHggPSBmcmVxLCB5ID0gcmVvcmRlcihWMV9sYWJlbCwgaW52YWRlXzFfZnJlcSksIGZpbGwgPSBmb3JjYXRzOjpmY3RfcmV2KGZhY3RvcihpbnZhc2lvbiwgbGV2ZWxzID0gYygiT25seSBzdHJhaW4gMSBpbnZhc2lvbiIsICJPbmx5IHN0cmFpbiAyIGludmFzaW9uIiwgIk11dHVhbCBpbnZhc2lvbiIsICJNdXR1YWwgbm9uLWludmFzaW9uIikpKSksIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgbGFicyh4ID0gIkZyZXF1ZW5jeSIsIGZpbGwgPSAiSW52YXNpb24iLCB5ID0gIlN0cmFpbiAxIGN1ZSIpICsKICB0aGVtZV9idygpICArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiT25seSBzdHJhaW4gMSBpbnZhc2lvbiIgPSAiIzQ1NzViNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT25seSBzdHJhaW4gMiBpbnZhc2lvbiIgPSAiI2ZjOGQ1OSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTXV0dWFsIGludmFzaW9uIiA9ICIjZmVlMDkwIikpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpCmBgYAoKIyBwbG90IHRvZ2V0aGVyCmBgYHtyfQppbnZhc2lvbi5wbCA8LSBnZ2FycmFuZ2UoaW52YXNpb24ucGwxLCBpbnZhc2lvbi5wbDIsIGFsaWduID0gImgiLCBjb21tb24ubGVnZW5kID0gVCwgd2lkdGhzID0gYygyLCAxKSkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vaW52YXNpb25faGVhdG1hcC50aWZmIiksIHdpZHRoID0gMTAsIGhlaWdodCA9IDYpCmBgYAoKIy0tLS0tLSBlZmZlY3QgY3VlIHBlcmNlcHRpb24gLS0tLS0tLSMKCiMgc3RhdGljCiMjIGxvZ2dpbmcKYGBge3J9CiMgZ2V0IG5vbi1sb2dnZWQgcGFpcmluZ3MKc3RhdGljX25vbG9nIDwtIHN0YXRpYy5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IHRyaW13cyhnc3ViKCJcXCAuKiIsICIiLCBsYWJlbF9jaV8xKSksCiAgICAgICAgIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpKSAlPiUgCiAgZmlsdGVyKGxvZ18xID09ICJub25lIikKCgpzdGF0aWNfbG9nIDwtIHN0YXRpYy5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IHRyaW13cyhnc3ViKCJcXCAuKiIsICIiLCBsYWJlbF9jaV8xKSksCiAgICAgICAgIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpKSAlPiUgCiAgZmlsdGVyKGxvZ18xID09ICJsb2ciKQoKc3RhdGljX2xvZy5kZiA8LSBsZWZ0X2pvaW4oCiAgc2VsZWN0KHN0YXRpY19ub2xvZywgY3VlXzEsIGxhYmVsX2NpXzIsIGxvZ18xLCBOb25lID0gZml0bmVzc19kaWZmZXJlbmNlKSwKICBzZWxlY3Qoc3RhdGljX2xvZywgY3VlXzEsIGxhYmVsX2NpXzIsIGxvZ18xLCBMb2cgPSBmaXRuZXNzX2RpZmZlcmVuY2UpLAogIGJ5ID0gYygiY3VlXzEiLCAibGFiZWxfY2lfMiIpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShOb25lKSAmICFpcy5uYShMb2cpKSAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gaWZlbHNlKExvZyA+IE5vbmUsICJMb2dnZWQgYmV0dGVyIiwgIk5vdCBsb2dnZWQgYmV0dGVyIikpCmBgYAoKIyBjb21iaW5lZApgYGB7cn0Kc3RhdGljX25vY29tYiA8LSBzdGF0aWMuZGYyICU+JSAKICBtdXRhdGUoY3VlXzEgPSBpZmVsc2UoCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJzdW0iKSwgIkkrSWciLAogICAgdHJpbXdzKGdzdWIoIisxLip8XFwgbG9nIiwgIiIsIGxhYmVsX2NpXzEpKQogICksCiAgbG9nXzEgPSBjYXNlX3doZW4oCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIikgfiAibG9nIiwKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciLCBuZWdhdGUgPSBUKSB+ICJub25lIiksCiAgICBjb21iXzEgPSBjYXNlX3doZW4oCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICIxK3xzdW0iKSB+ICJjb21iIiwKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgIjErfHN1bSIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiIAogICkpICU+JSAKICBmaWx0ZXIoY29tYl8xID09ICJub25lIikKCnN0YXRpY19jb21iIDwtIHN0YXRpYy5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IGlmZWxzZSgKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgInN1bSIpLCAiSStJZyIsCiAgICB0cmltd3MoZ3N1YigiKzEuKnxcXCBsb2ciLCAiIiwgbGFiZWxfY2lfMSkpCiAgKSwKICBsb2dfMSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciKSB+ICJsb2ciLAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiKSwKICAgIGNvbWJfMSA9IGNhc2Vfd2hlbigKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgIjErfHN1bSIpIH4gImNvbWIiLAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAiMSt8c3VtIiwgbmVnYXRlID0gVCkgfiAibm9uZSIgCiAgKSkgJT4lIAogIGZpbHRlcihjb21iXzEgPT0gImNvbWIiKQogIApzdGF0aWNfY29tYi5kZiA8LSBsZWZ0X2pvaW4oCiAgc2VsZWN0KHN0YXRpY19ub2NvbWIsIGN1ZV8xLCBsYWJlbF9jaV8yLCBsb2dfMSwgU2VsZiA9IGZpdG5lc3NfZGlmZmVyZW5jZSksCiAgc2VsZWN0KHN0YXRpY19jb21iLCBjdWVfMSwgbGFiZWxfY2lfMiwgbG9nXzEsIFRvdGFsID0gZml0bmVzc19kaWZmZXJlbmNlKSwKICBieSA9IGMoImN1ZV8xIiwgImxvZ18xIiwgImxhYmVsX2NpXzIiKSkgJT4lIAogIGZpbHRlcighaXMubmEoVG90YWwpICYgIWlzLm5hKFNlbGYpKSAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gaWZlbHNlKFRvdGFsID4gU2VsZiwgIlRvdGFsIGJldHRlciIsICJTZWxmIGJldHRlciIpKQpgYGAKCiMgcGxvdApgYGB7cn0Kc3RhdGljX2xvZy5wbCA8LSBnZ3BhaXJlZChzdGF0aWNfbG9nLmRmLCBjb25kMSA9ICJOb25lIiwgY29uZDIgPSAiTG9nIiwgbGluZS5jb2xvciA9ICJjbGFzc2lmaWNhdGlvbiIsIGFscGhhID0gMC41KSArCiAgbGFicyh4ID0gIkN1ZSBwZXJjZXB0aW9uIiwgeSA9ICJGaXRuZXNzIGRpZmZlcmVuY2UiLCBjb2xvciA9ICJFZmZlY3QiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIk5vdCBsb2dnZWQgYmV0dGVyIiA9ICIjZmM4ZDU5IiwgIkxvZ2dlZCBiZXR0ZXIiID0gIiM0NTc1YjQiKSkKCnN0YXRpY19jb21iLnBsIDwtIGdncGFpcmVkKHN0YXRpY19jb21iLmRmLCBjb25kMSA9ICJUb3RhbCIsIGNvbmQyID0gIlNlbGYiLCBsaW5lLmNvbG9yID0gImNsYXNzaWZpY2F0aW9uIiwgYWxwaGEgPSAwLjUpICsKICBsYWJzKHggPSAiQ3VlIHBlcmNlcHRpb24iLCB5ID0gIkZpdG5lc3MgZGlmZmVyZW5jZSIsIGNvbG9yID0gIkVmZmVjdCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVG90YWwgYmV0dGVyIiA9ICIjZmM4ZDU5IiwgIlNlbGYgYmV0dGVyIiA9ICIjNDU3NWI0IikpCgpzdGF0aWNfY3VlLnBsIDwtIGdnYXJyYW5nZShzdGF0aWNfbG9nLnBsLCBzdGF0aWNfY29tYi5wbCwgbmNvbCA9IDIsIGFsaWduID0gImgiKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9zdGF0aWNfY3VlX3BlcmNlcHRpb24udGlmZiIpLCB3aWR0aCA9IDcuNSwgaGVpZ2h0ID0gNCkKYGBgCgojIGludmFzaW9uCiMjIHByb2NlcyBkYXRhCmBgYHtyfQojIGpvaW4gaW52YWRlIGRmIHdpdGggbGFiZWwgYmVjYXVzZSBJIGFtIGxhenkKaW52YWRlLmRmMiA8LSBpbnZhZGUuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGlkX2NpLCBsYWJlbF9jaV8xID0gbGFiZWxfY2kpLCBieSA9IGMoIm11dF9pZCIgPSAiaWRfY2kiKSkKYGBgCgojIGxvZwpgYGB7cn0KIyBnZXQgbm9uLWxvZ2dlZCBwYWlyaW5ncwppbnZhZGVfbm9sb2cgPC0gaW52YWRlLmRmMiAlPiUgCiAgbXV0YXRlKGN1ZV8xID0gdHJpbXdzKGdzdWIoIlxcIC4qIiwgIiIsIGxhYmVsX2NpXzEpKSwKICAgICAgICAgbG9nXzEgPSBjYXNlX3doZW4oCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIikgfiAibG9nIiwKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciLCBuZWdhdGUgPSBUKSB+ICJub25lIikpICU+JSAKICBmaWx0ZXIobG9nXzEgPT0gIm5vbmUiKQoKCmludmFkZV9sb2cgPC0gaW52YWRlLmRmMiAlPiUgCiAgbXV0YXRlKGN1ZV8xID0gdHJpbXdzKGdzdWIoIlxcIC4qIiwgIiIsIGxhYmVsX2NpXzEpKSwKICAgICAgICAgbG9nXzEgPSBjYXNlX3doZW4oCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIikgfiAibG9nIiwKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciLCBuZWdhdGUgPSBUKSB+ICJub25lIikpICU+JSAKICBmaWx0ZXIobG9nXzEgPT0gImxvZyIpCgppbnZhZGVfbG9nLmRmIDwtIGxlZnRfam9pbigKICBzZWxlY3QoaW52YWRlX25vbG9nLCBjdWVfMSwgcmVzX2lkLCBsb2dfMSwgTm9uZSA9IGZpdG5lc3MpLAogIHNlbGVjdChpbnZhZGVfbG9nLCBjdWVfMSwgcmVzX2lkLCBsb2dfMSwgTG9nID0gZml0bmVzcyksCiAgYnkgPSBjKCJjdWVfMSIsICJyZXNfaWQiKSkgJT4lIAogIGZpbHRlcighaXMubmEoTm9uZSkgJiAhaXMubmEoTG9nKSkgJT4lIAogIG11dGF0ZShjbGFzc2lmaWNhdGlvbiA9IGlmZWxzZShMb2cgPiBOb25lLCAiTG9nZ2VkIGJldHRlciIsICJOb3QgbG9nZ2VkIGJldHRlciIpKQpgYGAKCiMgY29tYmluZWQKYGBge3J9CmludmFkZV9ub2NvbWIgPC0gaW52YWRlLmRmMiAlPiUgCiAgbXV0YXRlKGN1ZV8xID0gaWZlbHNlKAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAic3VtIiksICJJK0lnIiwKICAgIHRyaW13cyhnc3ViKCIrMS4qfFxcIGxvZyIsICIiLCBsYWJlbF9jaV8xKSkKICApLAogIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpLAogICAgY29tYl8xID0gY2FzZV93aGVuKAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAiMSt8c3VtIikgfiAiY29tYiIsCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICIxK3xzdW0iLCBuZWdhdGUgPSBUKSB+ICJub25lIiAKICApKSAlPiUgCiAgZmlsdGVyKGNvbWJfMSA9PSAibm9uZSIpCgppbnZhZGVfY29tYiA8LSBpbnZhZGUuZGYyICU+JSAKICBtdXRhdGUoY3VlXzEgPSBpZmVsc2UoCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJzdW0iKSwgIkkrSWciLAogICAgdHJpbXdzKGdzdWIoIisxLip8XFwgbG9nIiwgIiIsIGxhYmVsX2NpXzEpKQogICksCiAgbG9nXzEgPSBjYXNlX3doZW4oCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIikgfiAibG9nIiwKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciLCBuZWdhdGUgPSBUKSB+ICJub25lIiksCiAgICBjb21iXzEgPSBjYXNlX3doZW4oCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICIxK3xzdW0iKSB+ICJjb21iIiwKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgIjErfHN1bSIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiIAogICkpICU+JSAKICBmaWx0ZXIoY29tYl8xID09ICJjb21iIikKICAKaW52YWRlX2NvbWIuZGYgPC0gbGVmdF9qb2luKAogIHNlbGVjdChpbnZhZGVfbm9jb21iLCBjdWVfMSwgcmVzX2lkLCBsb2dfMSwgU2VsZiA9IGZpdG5lc3MpLAogIHNlbGVjdChpbnZhZGVfY29tYiwgY3VlXzEsIHJlc19pZCwgbG9nXzEsIFRvdGFsID0gZml0bmVzcyksCiAgYnkgPSBjKCJjdWVfMSIsICJsb2dfMSIsICJyZXNfaWQiKSkgJT4lIAogIGZpbHRlcighaXMubmEoVG90YWwpICYgIWlzLm5hKFNlbGYpKSAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gaWZlbHNlKFRvdGFsID4gU2VsZiwgIlRvdGFsIGJldHRlciIsICJTZWxmIGJldHRlciIpKQpgYGAKCiMgcGxvdApgYGB7cn0KaW52YWRlX2xvZy5wbCA8LSBnZ3BhaXJlZChpbnZhZGVfbG9nLmRmLCBjb25kMSA9ICJOb25lIiwgY29uZDIgPSAiTG9nIiwgbGluZS5jb2xvciA9ICJjbGFzc2lmaWNhdGlvbiIsIGFscGhhID0gMC41KSArCiAgbGFicyh4ID0gIkN1ZSBwZXJjZXB0aW9uIiwgeSA9ICJGaXRuZXNzIGRpZmZlcmVuY2UiLCBjb2xvciA9ICJFZmZlY3QiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIk5vdCBsb2dnZWQgYmV0dGVyIiA9ICIjZmM4ZDU5IiwgIkxvZ2dlZCBiZXR0ZXIiID0gIiM0NTc1YjQiKSkKCmludmFkZV9jb21iLnBsIDwtIGdncGFpcmVkKGludmFkZV9jb21iLmRmLCBjb25kMSA9ICJUb3RhbCIsIGNvbmQyID0gIlNlbGYiLCBsaW5lLmNvbG9yID0gImNsYXNzaWZpY2F0aW9uIiwgYWxwaGEgPSAwLjUpICsKICBsYWJzKHggPSAiQ3VlIHBlcmNlcHRpb24iLCB5ID0gIkZpdG5lc3MgZGlmZmVyZW5jZSIsIGNvbG9yID0gIkVmZmVjdCIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVG90YWwgYmV0dGVyIiA9ICIjZmM4ZDU5IiwgIlNlbGYgYmV0dGVyIiA9ICIjNDU3NWI0IikpCgppbnZhZGVfY3VlLnBsIDwtIGdnYXJyYW5nZShpbnZhZGVfbG9nLnBsLCBpbnZhZGVfY29tYi5wbCwgYWxpZ24gPSAiaCIsIG5jb2wgPSAyKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9pbnZhc2lvbl9jdWVfcGVyY2VwdGlvbi50aWZmIiksIHdpZHRoID0gNy41LCBoZWlnaHQgPSA0KQpgYGAKCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwojIFBhcnRpdGlvbmluZyBiZXN0IGN1ZQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSMKIy0tLS0tLS0gc2luZ2xlIGluZmVjdGlvbiAtLS0tLS0tLS0tLSMKIyByZWRvIHNvbWUgb3B0aW1pemF0aW9uIChsb3dlciBmaXRuZXNzIGluIG5vIFIgdGhhbiBkZWZhdWx0KQpgYGB7cn0Kc291cmNlKGhlcmUoImZ1bmN0aW9ucy9jaGFiYXVkaV9zaV9jbGVhbl9SLlIiKSkKc291cmNlKGhlcmUoImZ1bmN0aW9ucy9jaGFiYXVkaV9zaV9jbGVhbl9OLlIiKSkKIyBJIG5vbmUKY2wgPC0gbWFrZUNsdXN0ZXIoZGV0ZWN0Q29yZXMoKSk7IHNldERlZmF1bHRDbHVzdGVyKGNsID0gY2wpCklfbm9fUiA8LSBvcHRpbVBhcmFsbGVsKAogICAgcGFyID0gcmVwKDAuNSw0KSwgIyBzdGFydCBhdCAwLjV4NAogICAgZm4gPSBjaGFiYXVkaV9zaV9jbGVhbl9SLCAKICAgIGNvbnRyb2wgPSBsaXN0KHRyYWNlID0gNiwgZm5zY2FsZSA9IC0xKSwKICAgIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICAgIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogICAgdGltZV9yYW5nZSA9IHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICAgIGN1ZV9yYW5nZSA9ICBzZXEoMCwgNiooMTBeNiksIGJ5ID0gKDYqKDEwXjYpKS81MDAwKSwKICAgIGN1ZSA9ICJJIiwKICAgIGxvZ19jdWUgPSAibm9uZSIsCiAgICBzb2x2ZXIgPSAidm9kZSIpCnN0b3BDbHVzdGVyKGNsKQojIDAuMTQ0MDIxIC00My4xMDQ2IDIwMzAuMjcgLTUyNC42ODYgCiMgOC42OTU4OQpgYGAKCiMgaW1wb3J0IGFuZCBwcm9jZXNzIGRhdGEKYGBge3J9CiMgaW1wb3J0IGluIGRhdGEKc2lfcGFydGl0aW9uLmxzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvcGFydGl0aW9uL3NpLyIpLCBwYXR0ZXJuID0gIiouY3N2IiwgZnVsbC5uYW1lcyA9IFQpCnNpX3BhcnRpdGlvbi5scyA8LSBsYXBwbHkoc2lfcGFydGl0aW9uLmxzLCByZWFkLmNzdikKc2lfcGFydGl0aW9uLmRmIDwtIGRvLmNhbGwocmJpbmQsIHNpX3BhcnRpdGlvbi5scykKCiMgY29tYmluZSB3aXRoIHNpIGZpdG5lc3MgKGRlZmF1bHQpCnNpX3BhcnRpdGlvbi5kZiA8LSBzaV9wYXJ0aXRpb24uZGYgJT4lIGxlZnRfam9pbihzZWxlY3Qoc2lfZml0bmVzcy5kZiwgaWQsIGZpdG5lc3MgPSB2YWx1ZSksIGJ5ID0gImlkIikKCiMgbWFrZSBsb25nZXIKc2lfcGFydGl0aW9uLmRmMiA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKHNpX3BhcnRpdGlvbi5kZiwgYyhmaXRuZXNzX1IsIGZpdG5lc3NfTiwgZml0bmVzc19XLCBmaXRuZXNzKSkKCiMgY2FsY3VsYXRlIGNvZWZmaWNpZW50IG9mIHZhcmlhdGlvbi4gQWxzbyByZW5hbWUKc2lfcGFydGl0aW9uLmRmMiA8LSBzaV9wYXJ0aXRpb24uZGYyICU+JSAKICBncm91cF9ieShuYW1lKSAlPiUgCiAgbXV0YXRlKGN2ID0gc2QodmFsdWUpL21lYW4odmFsdWUpKjEwMCwKICAgICAgICAgbWVhbiA9IG1lYW4odmFsdWUpLAogICAgICAgICBjYXRlZ29yeSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBuYW1lID09ICJmaXRuZXNzX1IiIH4gIk5vIFJCQyBsaW1pdGF0aW9uIiwKICAgICAgICAgICBuYW1lID09ICJmaXRuZXNzX1ciIH4gIk5vIHRhcmdldGVkIGltbXVuaXR5IiwKICAgICAgICAgICBuYW1lID09ICJmaXRuZXNzX04iIH4gIk5vIGluZGlzY3JpbWluYXRlXG5pbW11bml0eSIsCiAgICAgICAgICAgbmFtZSA9PSAiZml0bmVzcyIgfiAiRGVmYXVsdCIKICAgICAgICAgKSkKCmBgYAoKIyBwbG90CmBgYHtyfQpsaWJyYXJ5KHVuZ2V2aXopCiMgcmF3IGZpdG5lc3MKc2lfcGFydGl0aW9uLnBsMSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV92cGxpbmUoZGF0YSA9IHNpX3BhcnRpdGlvbi5kZjIsIGFlcyh5ID0gZmN0X3Jlb3JkZXIoY2F0ZWdvcnksIG1lYW4pLCB4ID0gbWVhbiwgZ3JvdXAgPSBjYXRlZ29yeSwgY29sb3IgPSBjYXRlZ29yeSksIHNob3cubGVnZW5kID0gRiwgc2l6ZSA9IDEpICsKICBnZW9tX3BvaW50KGRhdGEgPSBzaV9wYXJ0aXRpb24uZGYyLCBhZXMoeSA9IGZjdF9yZW9yZGVyKGNhdGVnb3J5LCBtZWFuKSwgeCA9IHZhbHVlKSwgc2l6ZSA9IDIsIGFscGhhID0gMC43KSArCiAgZ2VvbV9saW5lKGRhdGEgPSBzaV9wYXJ0aXRpb24uZGYyLCBhZXMoeSA9IGZjdF9yZW9yZGVyKGNhdGVnb3J5LCBtZWFuKSwgeCA9IHZhbHVlLCBncm91cCA9IGlkKSwgYWxwaGEgPSAwLjIpICsKICBsYWJzKHggPSAiRml0bmVzcyIsIHkgPSAiQ29uZGl0aW9ucyIpICsKICB0aGVtZV9idygpCgojIGNvZWZmaWNpZW50IG9mIHZhcmlhdGlvbgpzaV9wYXJ0aXRpb24ucGwyIDwtIGdncGxvdCgpICsKICBnZW9tX2JhcihkYXRhID0gc2lfcGFydGl0aW9uLmRmMiwgYWVzKHkgPSBmY3RfcmVvcmRlcihjYXRlZ29yeSwgbWVhbiksIHggPSBjdiksIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgbGFicyh4ID0gIkNvZWZmaWNpZW50IG9mXG52YXJpYXRpb24gKCUpIiwgeSA9ICIiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSkKCnNpX3BhcnRpdGlvbi5wbCA8LSBnZ2FycmFuZ2Uoc2lfcGFydGl0aW9uLnBsMSwgc2lfcGFydGl0aW9uLnBsMiwgd2lkdGhzID0gYygxLCAwLjMpLCBhbGlnbiA9ICJoIikKc2lfcGFydGl0aW9uLnBsCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9wYXJ0aXRpb25fZml0bmVzcy50aWZmIiksIHdpZHRoID0gNywgaGVpZ2h0ID0gNCkKYGBgCgojLS0tLS0tLSBjb25zZXF1ZW5jZXMgb2Ygbm8gdGFyZ2V0ZWQgaW1tdW5pdHkgLS0tLS0tLS0tLS0tIwojIGdldCBkeW5hbWljcyBvZiBubyB0YXJnZXRlZCBpbW11bml0eQpgYGB7cn0KZ2V0X2R5biA8LSBmdW5jdGlvbihkZil7CiAgCiAgc291cmNlKGhlcmUoImZ1bmN0aW9ucy9jaGFiYXVkaV9zaV9jbGVhbl9XLlIiKSkKICBpZCA8LSBkZiRpZAogIGN1ZSA8LSBkZiRjdWUKICBsb2cgPC0gZGYkbG9nCiAgcGFyIDwtIGMoZGYkdmFyX1cxLCBkZiR2YXJfVzIsIGRmJHZhcl9XMywgZGYkdmFyX1c0KQogIGN1ZV9yYW5nZSA8LSBzZXEoZGYkbG93LCBkZiRoaWdoLCBieSA9IGRmJGJ5KQogIAogICMgZ2V0IGR5bmFtaWNzCiAgZHluIDwtIGNoYWJhdWRpX3NpX2NsZWFuX1coCiAgICBwYXJhbWV0ZXJzX2NyID0gcGFyLAogICAgaW1tdW5pdHkgPSAidHN1a3VzaGkiLAogICAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgICB0aW1lX3JhbmdlID0gc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogICAgY3VlX3JhbmdlID0gIGN1ZV9yYW5nZSwKICAgIGN1ZSA9IGN1ZSwKICAgIGxvZ19jdWUgPSBsb2csCiAgICBzb2x2ZXIgPSAidm9kZSIsCiAgICBkeW4gPSBUCiAgKQogIAogICMgY29tYmluZQogIGR5bjIgPC0gY2JpbmQoZHluLCBpZCA9IGlkLCBjdWUgPSBjdWUsIGxvZyA9IGxvZykKICAKICB3cml0ZV9wYXJxdWV0KGR5bjIsIHBhc3RlMChoZXJlKCJkYXRhL3BhcnRpdGlvbi9zaV9keW4vIiksIGlkLCAiX25vV19keW4ucGFycXVldCIpKQogIAp9CmBgYAoKIyBnZXQgZGYgdG8gcnVuCmBgYHtyfQojIGpvaW4gd2l0aCBjdWVfcmFuZ2UKY3VlX3JhbmdlX3NpLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY3VlX3JhbmdlX3NpLmNzdiIpKQpzaV9wYXJ0aXRpb24uZGYzIDwtIHNpX3BhcnRpdGlvbi5kZiAlPiUgbGVmdF9qb2luKHNlbGVjdChjdWVfcmFuZ2Vfc2kuZGYsIGxvdywgaGlnaCwgYnksIGlkKSwgImlkIikKCiMgbGFwcGx5IGxvb3AKc2lfcGFydGl0aW9uLmxzIDwtIHNwbGl0KHNpX3BhcnRpdGlvbi5kZjMsIHNlcShucm93KHNpX3BhcnRpdGlvbi5kZjMpKSkKbWNsYXBwbHkoc2lfcGFydGl0aW9uLmxzLCBnZXRfZHluKQpgYGAKCiMgcHJvY2VzcyBkYXRhZnJhbWUKYGBge3J9CiMgaW1wb3J0IGluIGRhdGFmcmFtZQpub19XLmxzIDwtIGxpc3QuZmlsZXMoaGVyZSgiZGF0YS9wYXJ0aXRpb24vc2lfZHluLyIpLCBwYXR0ZXJuID0gIipub1dfZHluLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKbm9fVy5kZiA8LSBsYXBwbHkobm9fVy5scywgcmVhZF9wYXJxdWV0KQpub19XLmRmIDwtIGRvLmNhbGwocmJpbmQsIG5vX1cuZGYpCgojIGNvbWJpbmUgd2l0aCBleiBsYWJlbAplel9sYWJlbCA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2V6X2xhYmVsLmNzdiIpKQpub19XLmRmIDwtIGxlZnRfam9pbihub19XLmRmLCBlel9sYWJlbCwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkKCiMgZ2V0IGNvbnZlcnNpb24gcmF0ZSAKbm9fVy5jciA8LSBub19XLmRmICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gImNyIikKbm9fVy5JIDwtIG5vX1cuZGYgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiSSIpCgojIGdldCBkZWZhdWx0IGNvbnZlcnNpb24gcmF0ZSBkeW5hbWljcwpzaV9keW4uZGYgPC0gbGVmdF9qb2luKHNpX2R5bi5kZiwgZXpfbGFiZWwsIGJ5ID0gYygiaWQiID0gImlkX3NpIikpCnNpX2R5bi5jciA8LSBzaV9keW4uZGYgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiY3IiKQpzaV9keW4uSSA8LSBzaV9keW4uZGYgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiSSIpCmBgYAoKIyBwbG90IGNvbnZlcnNpb24gcmF0ZQptZWNoYW5pc206IHRhcmdldGVkIGltbXVuaXR5IGxlZCB0byBsb3dlciBwYXJhc2l0ZSBkZW5zaXR5IGluIHRoZSBpbml0aWFsIHN0YWdlcywgd2hpY2ggcHJldmVudHMgcGFyYXNpdGVzIGZyb20gbWFraW5nIHRoZSBzd2l0Y2ggZnJvbSBubyBjb252ZXJzaW9uIHJhdGUgdG8gaGlnaCBjb252ZXJzaW9uIHJhdGUuIFdoZW4gcGFyc2l0ZSBkZW5zaXR5IHVuZGVyZ29lcyBkcmFzdGljIGluY3JlYXNlIGF0IHRoZSBiZWdpbm5pbmcgZHVlIHRvIGxvd2VyIGltbXVuaXR5LCB0aGlzIHByZXNlbnRzIGEgaGlnaGVyIGRlZ3JlZSBvZiBzaWduYWwgdGhhdCBhbGxvd3MgcGFyYXNpdGUgdG8gbWFrZSB0aGUgc3dpdGNoIGFwcHJvcHJpYXRlbHkKYGBge3J9CnBhcnRpdGlvbl9jci5wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBub19XLmNyLCBhZXMoeCA9IHRpbWUsIHk9IHZhbHVlLCBjb2xvciA9ICJObyB0YXJnZXRlZCBpbW11bml0eSIpKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBzaV9keW4uY3IsIGFlcyh4ID0gdGltZSwgeT0gdmFsdWUsIGNvbG9yID0gIkRlZmF1bHQiKSkgKwogIGZhY2V0X3dyYXAofmV6X2xhYmVsX3NpLCBuY29sID0gNSkgKwogIHhsaW0oMCwgMjApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA3KSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJDb252ZXJzaW9uIHJhdGUiLCBjb2xvciA9ICJDb25kaXRpb24iKSArCiAgdGhlbWVfYncoKQoKbm9fVy5jcgpgYGAKCiMtLS0tLSBjdWUgc3RhdGUgLS0tLS0tLS0tLS0tLS0jCgojIGZ1bmN0aW9uIHRvIGdldCBjdWUgc3RhdGVzCmBgYHtyfQojIGZ1bmN0aW9uIHRvIGdldCBjdWUgc3RhdGVzCmdldF9jdWVfc3RhdGUgPC0gZnVuY3Rpb24oZGYpewogIGN1ZSA8LSB0cmltd3MoZ3N1YigiX2xvZ3xfbm9uZSIsICIiLCB1bmlxdWUoZGYkaWQpKSkKICBpZihjdWUgIT0gIkkrSWciKXsKICBkZjIgPC0gZGYgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSBjdWUpCiAgaWYoc3RyX2RldGVjdCh1bmlxdWUoZGYkaWQpLCAibG9nIikpewogICAgZGYyIDwtIGRmMiAlPiUgCiAgICAgIG11dGF0ZSh2YWx1ZSA9IGxvZzEwKHZhbHVlKSkKICB9CiAgfQogIAogIGlmKGN1ZSA9PSAiSStJZyIpewogICAgZGYyIDwtIGRmICU+JSBmaWx0ZXIodmFyaWFibGUgJWluJSBjKCJJIiwgIklnIikpICU+JSAKICAgICAgZ3JvdXBfYnkodGltZSkgJT4lIAogICAgICBtdXRhdGUodmFsdWUgPSBzdW0odmFsdWUpKQogICAgCiAgICBpZihzdHJfZGV0ZWN0KHVuaXF1ZShkZiRpZCksICJsb2ciKSl7CiAgICBkZjIgPC0gZGYyICU+JSAKICAgICAgbXV0YXRlKHZhbHVlID0gbG9nMTAodmFsdWUpKQogIH0KICB9CiAgCiAgZGYyJHZhbHVlW2RmMiR2YWx1ZSA9PSAtSW5mXSA8LSAwCiAgCiAgd3JpdGVfcGFycXVldChkZjIsIHBhc3RlMChoZXJlKCJkYXRhL3BhcnRpdGlvbi9zaV9kZWZhdWx0X3N0YXRlLyIpLCB1bmlxdWUoZGYkaWQpLCAiX25vV19zdGF0ZS5wYXJxdWV0IikpCn0KYGBgCgojIHJ1biBmdW5jdGlvbgpgYGB7cn0KIyBzcGxpdCBkeW5hbWljcyBiYXNlZCBvbiBpZApub19XLnNwbGl0IDwtIHNwbGl0KG5vX1cuZGYsIG5vX1cuZGYkaWQpCgojIHJ1biBmdW5jdGlvbgptY2xhcHBseShub19XLnNwbGl0LCBnZXRfY3VlX3N0YXRlKQoKIyBnZXQgZGF0YWZyYW1lCm5vX1cuc3RhdGUgPC0gbGlzdC5maWxlcyhoZXJlKCJkYXRhL3BhcnRpdGlvbi9zaV9zdGF0ZS8iKSwgcGF0dGVybiA9ICIqLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKbm9fVy5zdGF0ZSA8LSBsYXBwbHkobm9fVy5zdGF0ZSwgcmVhZF9wYXJxdWV0KQpub19XLnN0YXRlIDwtIGRvLmNhbGwocmJpbmQsIG5vX1cuc3RhdGUpCm5vX1cuc3RhdGUkdmFsdWVbbm9fVy5zdGF0ZSR2YWx1ZSA8IDBdIDwtIDAKCiMgZ2V0IHNhbWUgZm9yIHNpIGluZmVjdGlvbgpkZWZhdWx0LnNwbGl0IDwtIHNwbGl0KHNpX2R5bi5kZiwgc2lfZHluLmRmJGlkKQptY2xhcHBseShkZWZhdWx0LnNwbGl0LCBnZXRfY3VlX3N0YXRlKQpkZWZhdWx0LnN0YXRlIDwtIGxpc3QuZmlsZXMoaGVyZSgiZGF0YS9wYXJ0aXRpb24vc2lfZGVmYXVsdF9zdGF0ZS8iKSwgcGF0dGVybiA9ICIqLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKZGVmYXVsdC5zdGF0ZSA8LSBsYXBwbHkoZGVmYXVsdC5zdGF0ZSwgcmVhZF9wYXJxdWV0KQpkZWZhdWx0LnN0YXRlIDwtIGRvLmNhbGwocmJpbmQsIGRlZmF1bHQuc3RhdGUpCmRlZmF1bHQuc3RhdGUkdmFsdWVbZGVmYXVsdC5zdGF0ZSR2YWx1ZSA8IDBdIDwtIDAKCiMgbWFudWFsbHkgY29ycmVjdCBub24tbG9nZ2luZwpJX0lnLmNvcnIgPC0gbm9fVy5zdGF0ZSAlPiUgZmlsdGVyKGlkID09ICJJK0lnX2xvZyIpICU+JSAKICBtdXRhdGUodmFsdWUgPSBsb2cxMCh2YWx1ZSkpCklfSWcuY29yciR2YWx1ZVtJX0lnLmNvcnIkdmFsdWUgPCAwXSA8LSAwCgpub19XLnN0YXRlMiA8LSBub19XLnN0YXRlICU+JSBmaWx0ZXIoaWQgIT0gIkkrSWdfbG9nIikKbm9fVy5zdGF0ZTIgPC0gbm9fVy5zdGF0ZTIgJT4lIHJiaW5kKG5vX1cuc3RhdGUyLCBJX0lnLmNvcnIpCmBgYAoKIyBwbG90CmFic2VuY2Ugb2YgdGFyZ2V0ZWQgaW1tdW5pdHkgbGVkIHRvIGRyYXN0aWMgaW5jcmVhc2UgaW4gcGFyYXNpdGUgZGVuc2l0eSBpbiBlYXJseSBwaGFzZXMgb2YgaW5mZWN0aW9uLiBUaGlzIHByb2R1Y2VzIGhpZ2ggc2lnbmFsIGludGVuc2l0eSBmb3IgcGFyYXNpdGUgYW5kIGhvc3QtYmFzZWQgY3VlcywgZXNwZWNpYWxseSBub24tbG9nZ2VkIG9uZXMsIHdoaWNoIGFsbG93cyBmb3Igc3RhdGUgZGlmZmVyZW50YXRpb24uIFdoaWxlIHRoaXMgY2FuIGJlIHZpZXdlZCBhcyBhIG1vZGVsbGluZyBhcnRpZmlhY3QsIGl0IHNob3VsZCBiZSBub3RlZCB0aGF0IHRoZSBsb2dnZWQgY3VlcyBzZWxkb20gY2hhbmdlZCBhcyB0aGVzZSBjaGFuZ2VzIGluIGVhcmx5IGluZmVjdGlvbiBkaWQgbGl0dGxlIHRvIGFsdGVyIHRoZSBhY3R1YWwgZWFybHkgc2lnbmFsIGludGVuc2l0eSBzZW5zZWQgYnkgdGhlIHBhcmFzaXRlLiBJbiBhbiBlbnZpcm9ubWVudCB3aGVyZSB0aGVyZSBpcyBoZXRlcm9nZW5laXR5IGluIGhvc3QgcmVzcG9uc2UsIGFuZCB0aHVzLCBzaWduYWwsIGxvZ2dpbmcgYWxsb3dzIGZvciBwYXJhc2l0ZXMgdG8gYWRhcHQgb3B0aW1hbCBzdHJhdGVneSB3aGVyZWFzIG5vbi1sb2dnZWQgY3VlcyBtdXN0IGNvbnRlbmQgd2l0aCBzZW5zaXRpdml0eSB0byBpbW11bml0eS4KYGBge3J9CiMgZnVuY3Rpb24gdG8gaW5kaXZpZHVhbGx5IHBsb3Qgc3R1ZmYKcGxvdF9zdGF0ZSA8LSBmdW5jdGlvbihkZjEsIGRmMil7CiAgCiAgIyBwbG90IHN0YXRlIGR5bmFtaWNzCiAgc3RhdGVfcGwgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZGYxLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSwgY29sb3IgPSBuYW1lLCBncm91cCA9IG5hbWUpKSArCiAgZmFjZXRfd3JhcCh+ZXpfbGFiZWxfc2ksIHNjYWxlcyA9ICJmcmVlIikgKwogIHhsaW0oMSwyMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICBsYWJzKHggPSAiIiwgeSA9ICJDdWUiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID1jKCJEZWZhdWx0IiA9ICIjNDU3NWI0IiwgIk5vIHRhcmdldGVkXG5pbW11bml0eSIgPSAiI2ZjOGQ1OSIpKQogIAogICMgcGxvdCBjb252ZXJzaW9uIHJhdGUgZHluYW1pY3MKICBjcl9wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9yYXN0ZXIoZGF0YSA9IGRmMiwgYWVzKHggPSB0aW1lLCB5ID0gbmFtZSwgZmlsbCA9IHZhbHVlKSkgKwogIHhsaW0oMSwyMCkgKwogIHRoZW1lX2J3KCkgKwogICAgbGFicyh4ID0gIlRpbWUgKGRheXMpIikgKwogIHRoZW1lKGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgIHNjYWxlX2ZpbGxfdmlyaWRpc19jKGxpbSA9IGMoMCwgMSkpCiAgCiAgIyBhcnJhbmdlCiAgZ2dhcnJhbmdlKHN0YXRlX3BsLCBjcl9wbCwgbmNvbCA9IDEsIG5yb3cgPSAyLCBhbGlnbiA9ICJ2IiwgaGVpZ2h0cyA9IGMoMSwgMC40KSkKICBnZ3NhdmUocGFzdGUwKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vcGFydGl0aW9uLyIpLCB1bmlxdWUoZGYxJGlkKSwgIi50aWZmIiksIHdpZHRoID0gNC41LCBoZWlnaHQgPSAzLjUpCn0KYGBgCgojIHNwbGl0CmBgYHtyfQojIGNvbWJpbmUgc3RhdGUKbm9XX2RlZmF1bHQuc3RhdGUgPC0gbGVmdF9qb2luKAogIHNlbGVjdChub19XLnN0YXRlMiwgdGltZSwgYE5vIHRhcmdldGVkXG5pbW11bml0eWAgPSB2YWx1ZSwgaWQsIGV6X2xhYmVsX3NpKSwgCiAgc2VsZWN0KGRlZmF1bHQuc3RhdGUgJT4lIGZpbHRlcih0aW1lIDw9IDIwKSwgdGltZSwgYERlZmF1bHRgID0gdmFsdWUsIGlkLCBlel9sYWJlbF9zaSksIGJ5ID0gYygidGltZSIsICJpZCIsICJlel9sYWJlbF9zaSIpKQoKbm9XX2RlZmF1bHQuc3RhdGUyIDwtIHRpZHlyOjpwaXZvdF9sb25nZXIobm9XX2RlZmF1bHQuc3RhdGUsIGMoYE5vIHRhcmdldGVkXG5pbW11bml0eWAsIGBEZWZhdWx0YCkpCiMgY29tYmluZSBjb252ZXJzaW9uIHJhc3Rlcgpub1dfZGVmYXVsdC5jciA8LSBsZWZ0X2pvaW4oCiAgc2VsZWN0KG5vX1cuY3IsIHRpbWUsIGBObyB0YXJnZXRlZFxuaW1tdW5pdHlgID0gdmFsdWUsIGlkLCBlel9sYWJlbF9zaSksIAogIHNlbGVjdChzaV9keW4uY3IgJT4lIGZpbHRlcih0aW1lIDw9IDIwKSwgdGltZSwgYERlZmF1bHRgID0gdmFsdWUsIGlkLCBlel9sYWJlbF9zaSksIGJ5ID0gYygidGltZSIsICJpZCIsICJlel9sYWJlbF9zaSIpKQpub1dfZGVmYXVsdC5jcjIgPC0gdGlkeXI6OnBpdm90X2xvbmdlcihub1dfZGVmYXVsdC5jciwgYyhgTm8gdGFyZ2V0ZWRcbmltbXVuaXR5YCwgYERlZmF1bHRgKSkKCiMgc3BsaXQKbm9XX2RlZmF1bHRfc3RhdGUubHMgPC0gc3BsaXQobm9XX2RlZmF1bHQuc3RhdGUyLCBub1dfZGVmYXVsdC5zdGF0ZTIkaWQpCm5vV19kZWZhdWx0X2NyLmxzIDwtIHNwbGl0KG5vV19kZWZhdWx0LmNyMiwgbm9XX2RlZmF1bHQuY3IyJGlkKQoKIyBydW4gZnVuY3Rpb24KbWFwcGx5KHBsb3Rfc3RhdGUsIG5vV19kZWZhdWx0X3N0YXRlLmxzLCBub1dfZGVmYXVsdF9jci5scykKYGBgCgojLS0tLS0tLS0gcmVhY3Rpb24gbm9ybXMgb2YgZGVmYXVsdCB2cyBvcHRpbWl6ZWQgLS0tLS0tLS0tLS0tIwojIGdldCByZWFjdGlvbiBub3JtIGFuZCBydWcgZGF0YQpgYGB7cn0Kc291cmNlKGhlcmUoImZ1bmN0aW9ucy9wYXJfdG9fZGYuUiIpKQoKIyBHYW1ldG9jeXRlCmdfbG9nLnJuIDwtIHBhcl90b19kZihwYXIgPSBjKDEuMjExNTIxLAktMy45MzY3NzgsCS0xLjMxMjk0NCwJLTEuMjg1NzEzKSwgY3VlX3JhbmdlID0gc2VxKDAsIGxvZzEwKDYqKDEwXjQpKSwgYnkgPSAobG9nMTAoNiooMTBeNCkpKS81MDAwKSkKZ19sb2cucm4yIDwtIHBhcl90b19kZihwYXIgPSBjKDEuMzkzODYwNTM5LAktNC4yNTMwMDc2MTYsCS0wLjMxMzk0NzAyOSwJLTIuMDAwODU3MzQ0KSwgY3VlX3JhbmdlID0gc2VxKDAsIGxvZzEwKDYqKDEwXjQpKSwgYnkgPSAobG9nMTAoNiooMTBeNCkpKS81MDAwKSkKCmcucm4gPC0gcGFyX3RvX2RmKHBhciA9IGMoMC4wNDA2MTI4OCwJLTkuMzE0NDU5NTgsCTc0LjEzMDE1NTA2LAktNDMxLjU5ODQzNjQpLCBjdWVfcmFuZ2UgPSBzZXEoMCwgNiooMTBeNCksIGJ5ID0gKDYqKDEwXjQpKS81MDAwKSkKZy5ybjIgPC0gcGFyX3RvX2RmKHBhciA9IGMoMC41NDE3MjkwNzMsCS0zLjkwNDYxNjQ0MywJMC44NzQ4NzQxMiwJLTAuNjk0MTc3MDIxKSwgY3VlX3JhbmdlID0gc2VxKDAsIDYqKDEwXjQpLCBieSA9ICg2KigxMF40KSkvNTAwMCkpCgojIEkrSWcKSV9JZ19sb2cucm4gPC0gcGFyX3RvX2RmKHBhciA9IGMoMy41OTQwNDIsCTQuMTU3NzQ0LAktMTMuNTMwNjcyLAkyLjU5OTkwNSksIGN1ZV9yYW5nZSA9IHNlcSgwLCBsb2cxMCg2KigxMF42KSksIGJ5ID0gKGxvZzEwKDYqKDEwXjYpKSkvNTAwMCkpCklfSWdfbG9nLnJuMiA8LSBwYXJfdG9fZGYocGFyID0gYyg2My43MTg5MzgyMiwJLTg3Ljc3NjcxNjAxLAktNTYuNTU0NzU1MTQsCS02Ni4wMjIwOTU0OSksIGN1ZV9yYW5nZSA9IHNlcSgwLCBsb2cxMCg2KigxMF42KSksIGJ5ID0gKGxvZzEwKDYqKDEwXjYpKSkvNTAwMCkpCgpJX0lnLnJuIDwtIHBhcl90b19kZihwYXIgPSBjKDAuMzE1OTI5NywJLTQ2LjExMDQ1NTgsCTEyNTAuNzUyOTA4LAktNi4xOTgyMDkzKSwgY3VlX3JhbmdlID0gc2VxKDAsIDYqKDEwXjYpLCBieSA9ICg2KigxMF42KSkvNTAwMCkpCklfSWcucm4yIDwtIHBhcl90b19kZihwYXIgPSBjKDAuNzMxOTgyNzg0LAktMjEuNjk3OTk0NDksCTE0OS43ODQxODc2LAkxNy4wMjU1MTc2OSksIGN1ZV9yYW5nZSA9IHNlcSgwLCA2KigxMF42KSwgYnkgPSAoNiooMTBeNikpLzUwMDApKQoKIyBjb252ZXJ0IGxvZyB0byBub24tbG9nZ2VkIHNjYWxlCmdfbG9nLnJuJGN1ZV9yYW5nZSA8LSAxMF4oZ19sb2cucm4kY3VlX3JhbmdlKQpnX2xvZy5ybjIkY3VlX3JhbmdlIDwtIDEwXihnX2xvZy5ybjIkY3VlX3JhbmdlKQpJX0lnX2xvZy5ybiRjdWVfcmFuZ2UgPC0gMTBeKElfSWdfbG9nLnJuJGN1ZV9yYW5nZSkKSV9JZ19sb2cucm4yJGN1ZV9yYW5nZSA8LSAxMF4oSV9JZ19sb2cucm4yJGN1ZV9yYW5nZSkKCiMgZ2V0IHJ1ZwpnX2xvZy5ydWcgPC0gZGVmYXVsdC5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJHIGxvZyIpICU+JSAKICBtdXRhdGUodmFsdWUgPSAxMF52YWx1ZSkgJT4lIAogIHNlbGVjdChsYWJlbF9zaSwgdmFsdWUpCgpnX2xvZy5ydWcyIDwtIG5vX1cuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiRyBsb2ciKSAlPiUgCiAgbXV0YXRlKHZhbHVlID0gMTBedmFsdWUpICU+JSAKICBmaWx0ZXIodmFsdWUgPD0gNiooMTBeNCkpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKSV9JZ19sb2cucnVnIDwtIGRlZmF1bHQuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiSStJZyBsb2ciKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpLCB2YWx1ZSkKCklfSWdfbG9nLnJ1ZzIgPC0gbm9fVy5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJJK0lnIGxvZyIpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKZy5ydWcgPC0gZGVmYXVsdC5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJHIikgJT4lIAogIHNlbGVjdChsYWJlbF9zaSwgdmFsdWUpCgpnLnJ1ZzIgPC0gbm9fVy5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJHIiAmIHZhbHVlIDw9IDYqKDEwXjQpKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpLCB2YWx1ZSkKCklfSWcucnVnIDwtIGRlZmF1bHQuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiSStJZyIpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKSV9JZy5ydWcyIDwtIG5vX1cuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiSStJZyIpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKIyBnZXQgcnVnIGxpbWl0cwpydWdfbGltIDwtIHJiaW5kKGdfbG9nLnJ1ZywKICAgICAgICAgICAgICAgICBnX2xvZy5ydWcyLAogICAgICAgICAgICAgICAgIElfSWdfbG9nLnJ1ZywKICAgICAgICAgICAgICAgICBJX0lnX2xvZy5ydWcyLAogICAgICAgICAgICAgICAgIGcucnVnLAogICAgICAgICAgICAgICAgIGcucnVnMiwKICAgICAgICAgICAgICAgICBJX0lnLnJ1ZywKICAgICAgICAgICAgICAgICBJX0lnLnJ1ZzIpICU+JSAKICBncm91cF9ieShsYWJlbF9zaSkgJT4lIAogIHN1bW1hcml6ZShtYXggPSBtYXgoaGFibGFyOjpzKHZhbHVlKSwgbmEucm0gPSBUKSwKICAgICAgICAgICAgbWluID0gbWluKGhhYmxhcjo6cyh2YWx1ZSksIG5hLnJtID0gVCkpCgojIGNvbWJpbmUgYW5kIGZpbHRlcgpybiA8LSByYmluZCgKICBjYmluZChnX2xvZy5ybiwgbGFiZWxfc2kgPSAiRyBsb2ciLCBjb25kaXRpb24gPSAiRGVmYXVsdCIpLAogIGNiaW5kKGdfbG9nLnJuMiwgbGFiZWxfc2kgPSAiRyBsb2ciLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiksCiAgY2JpbmQoZy5ybiwgbGFiZWxfc2kgPSAiRyIsIGNvbmRpdGlvbiA9ICJEZWZhdWx0IiksCiAgY2JpbmQoZy5ybjIsIGxhYmVsX3NpID0gIkciLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiksCiAgY2JpbmQoSV9JZ19sb2cucm4sIGxhYmVsX3NpID0gIkkrSWcgbG9nIiwgY29uZGl0aW9uID0gIkRlZmF1bHQiKSwKICBjYmluZChJX0lnX2xvZy5ybjIsIGxhYmVsX3NpID0gIkkrSWcgbG9nIiwgY29uZGl0aW9uID0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpLAogIGNiaW5kKElfSWcucm4sIGxhYmVsX3NpID0gIkkrSWciLCBjb25kaXRpb24gPSAiRGVmYXVsdCIpLAogIGNiaW5kKElfSWcucm4yLCBsYWJlbF9zaSA9ICJJK0lnIiwgY29uZGl0aW9uID0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpCikgJT4lIAogIGxlZnRfam9pbihydWdfbGltLCBieSA9ICJsYWJlbF9zaSIpICU+JSAKICBncm91cF9ieShsYWJlbF9zaSkgJT4lIAogIGZpbHRlcihjdWVfcmFuZ2UgPD0gbWF4ICYgY3VlX3JhbmdlID49IG1pbikKCiMgY29tYmluZSBydWcKcnVnIDwtIHJiaW5kKGNiaW5kKGdfbG9nLnJ1ZywgY29uZGl0aW9uID0gIkRlZmF1bHQiKSwKICAgICAgICAgICAgIGNiaW5kKGdfbG9nLnJ1ZzIsIGNvbmRpdGlvbiA9ICJObyB0YXJnZXRlZFxuaW1tdW5pdHkiKSwKICAgICAgICAgICAgIGNiaW5kKGcucnVnLCBjb25kaXRpb24gPSAiRGVmYXVsdCIpLAogICAgICAgICAgICAgY2JpbmQoZy5ydWcyLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiksCiAgICAgICAgICAgICBjYmluZChJX0lnX2xvZy5ydWcsIGNvbmRpdGlvbiA9ICJEZWZhdWx0IiksCiAgICAgICAgICAgICBjYmluZChJX0lnX2xvZy5ydWcyLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiksCiAgICAgICAgICAgICBjYmluZChJX0lnLnJ1ZywgY29uZGl0aW9uID0gIkRlZmF1bHQiKSwKICAgICAgICAgICAgIGNiaW5kKElfSWcucnVnMiwgY29uZGl0aW9uID0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpKQoKIyBjb2JpbmUgd2l0aCBlemxhYmVsCnJuMiA8LSBybiAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9ICJsYWJlbF9zaSIpCnJ1ZzIgPC0gcnVnICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gImxhYmVsX3NpIikKCiMgZmlsdGVyIHJ1ZwpkZWZhdWx0LnJ1ZyA8LSBydWcyICU+JSBmaWx0ZXIoY29uZGl0aW9uID09ICJEZWZhdWx0IikKbm8ucnVnIDwtIHJ1ZzIgJT4lIGZpbHRlcihjb25kaXRpb24gPT0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpCmBgYAoKIyBwbG90CmBgYHtyfQpnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBybjIsIGFlcyh4ID0gY3VlX3JhbmdlLCB5ID0gY3IsIGNvbG9yID0gY29uZGl0aW9uKSkgKwogIGdlb21fcnVnKGRhdGEgPSBkZWZhdWx0LnJ1ZywgYWVzKHggPSB2YWx1ZSwgY29sb3IgPSBjb25kaXRpb24pLCBzaWRlcyA9ICJiIikgKwogIGdlb21fcnVnKGRhdGEgPSBuby5ydWcsIGFlcyh4ID0gdmFsdWUsIGNvbG9yID0gY29uZGl0aW9uKSwgc2lkZXMgPSAidCIpICsKICBmYWNldF93cmFwKH5mY3RfcmVsZXZlbChlel9sYWJlbF9zaSwgYygiR2FtZXRvY3l0ZSBsb2cxMCIsICJHYW1ldG9jeXRlIiwgIkFzZXh1YWwmc2V4dWFsXG5pUkJDIGxvZzEwIiwgIkFzZXh1YWwmc2V4dWFsIGlSQkMiKSksIHNjYWxlcyA9ICJmcmVlX3giKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpICsKICB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID1jKCJEZWZhdWx0IiA9ICIjNDU3NWI0IiwgIk5vIHRhcmdldGVkXG5pbW11bml0eSIgPSAiI2ZjOGQ1OSIpKSArCiAgeWxpbSgwLCAxLjEpICsKICBsYWJzKHggPSAiQ3VlIHJhbmdlIiwgeSA9ICJDb252ZXJzaW9uIHJhdGUiLCBjb2xvciA9ICJDb25kaXRpb24iKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vcGFydGl0aW9uX3JuLnRpZmYiKSwgd2lkdGggPSA3LjUsIGhlaWdodCA9IDYpCmBgYAoKIyBnZXQgY29udmVyc2lvbiByYXRlIGxlZ2VuZApgYGB7cn0Kbm9XX2RlZmF1bHQuY3IgJT4lIGZpbHRlcihpZCA9PSAiR19sb2ciKSAlPiUgCmdncGxvdCgpICsKICBnZW9tX3Jhc3RlcihhZXMoeCA9IHRpbWUsIHkgPSBpZCwgZmlsbCA9IERlZmF1bHQpKSArCiAgeGxpbSgxLDIwKSArCiAgdGhlbWVfYncoKSArCiAgICBsYWJzKHggPSAiVGltZSAoZGF5cykiLAogICAgICAgICBmaWxsID0gIkNvbnZlcnNpb24gcmF0ZSIpICsKICB0aGVtZShheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksKSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhsaW0gPSBjKDAsIDEpKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vY3JfbGVnZW5kLnRpZmYiKSkKYGBgCgojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSMKQmVzdCBjdWUgYWRvcHRpb24gY29uc2VxdWVuY2VzCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwojIGdldCBkYXRhIGZvciBkaXNlYXNlIGN1cnZlcwpgYGB7cn0KIyBzaW5nbGUgaW5mZWN0aW9uIGR5bmFtaWNzCnNpX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9zaV9keW4vc2lfZHluXzMwLnBhcnF1ZXQiKSkgCgojIGNvLWluZmVjdGlvbiBkeW5hbWljcyAobW9uLWN1ZSkKY2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2NpX2R5bi9jaV9keW4ucGFycXVldCIpKQoKIyBkdWFsIGN1ZSBkeW5hbWljcwpkdWFsX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kdWFsX2N1ZV9keW4vZHVhbF9jdWVfZHluLnBhcnF1ZXQiKSkKYGBgCgojLS0tLS0tLSBzaW5nbGUgY3VlIGNvbXBhcmlzb24gLS0tLS0tLS0tLS0tLS0tIwojIHByb2Nlc3MgZGF0YQpgYGB7cn0KIyBnZXQgY2xhc3NpZmljYXRpb24Kc2lfY3VlLmR2IDwtIHNpX2ZpdG5lc3MuZGYgJT4lIAogIG11dGF0ZShjbGFzc2lmaWNhdGlvbiA9IGNhc2Vfd2hlbigKICAgIHZhbHVlID4gOS4yIH4gIkhpZ2gtcGVyZm9ybWluZyIsCiAgICB2YWx1ZSA8PSA5LjIgfiAiUG9vci1wZXJmb3JtaW5nIgogICkpCgojIHByb2Nlc3MgZHluYW1pY3MgLT4gdHVybiBza2lubnkKc2lfZGMuZGYgPC0gc2lfZHluLmRmICU+JSAKICBmaWx0ZXIodmFyaWFibGUgPT0gIkkiIHwgdmFyaWFibGUgPT0gIklnIiB8IHZhcmlhYmxlID09ICJSIikgJT4lIAogIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdmFyaWFibGUsIHZhbHVlc19mcm9tID0gdmFsdWUpICU+JSAKICBtdXRhdGUodG90YWwgPSBJK0lnKQoKIyBqb2luIHdpdGggY2xhc3NpZmljYWl0b24Kc2lfZGMuZGYyIDwtIHNpX2RjLmRmICU+JSBsZWZ0X2pvaW4oc2VsZWN0KHNpX2N1ZS5kdiwgaWQsIGNsYXNzaWZpY2F0aW9uKSwgYnkgPSAiaWQiKQpzaV9jdWUuZHYKIyBzcGxpdCBpbnRvIHRvcCBlcmZvcm1pbmcgYW5kIHBvb3ItcGVyZm9ybWluZyBjdWVzCnNpX2RjLmhpZ2ggPC0gc2lfZGMuZGYyICU+JSBmaWx0ZXIoY2xhc3NpZmljYXRpb24gPT0gIkhpZ2gtcGVyZm9ybWluZyIpCnNpX2RjLnBvb3IgPC0gc2lfZGMuZGYyICU+JSBmaWx0ZXIoY2xhc3NpZmljYXRpb24gPT0gIlBvb3ItcGVyZm9ybWluZyIpCgojIGpvaW4gaGlnaCBwZXJmb3JtaW5nIHdpdGggbGFiZWwKc2lfZGMuaGlnaCA8LSBzaV9kYy5oaWdoICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwgJT4lIGRpc3RpbmN0KGxhYmVsX3NpLCAua2VlcF9hbGwgPSBUKSwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkKCiN3cml0ZV9wYXJxdWV0KHNpX2RjLmhpZ2gsIGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9zaV9kY19oaWdoLnBhcnF1ZXQiKSkKI3dyaXRlX3BhcnF1ZXQoc2lfZGMucG9vciwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL3NpX2RjX3Bvb3IucGFycXVldCIpKQpgYGAKCiMgcGxvdApgYGB7cn0Kc2lfZGMucG9vciA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL3NpX2RjX3Bvb3IucGFycXVldCIpKQpzaV9kYy5oaWdoIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvc2lfZGNfaGlnaC5wYXJxdWV0IikpCgojIHBsb3QKc2lfZGMucHJlIDwtIGdncGxvdCgpICsKICBnZW9tX3BhdGgoZGF0YSA9IHNpX2RjLnBvb3IsIGFlcyh4PSB0b3RhbCwgeSA9IFIsIGdyb3VwID0gaWQpLCBjb2xvciA9ICJkYXJrIGdyZXkiLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICBsYWJzKGNvbG9yID0gIlNpbmdsZSBpbmZlY3Rpb25cbmhpZ2gtcGVyZm9ybWluZyBjdWVzIiwgeCA9ICJBc2V4dWFsICYgc2V4dWFsIGlSQkMiLCB5ID0gIlJCQyIpICsKICB0aGVtZV9idygpKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFLCBhY2N1cmFjeSA9IDAuMSkpICsKICBndWlkZXMoc2hhcGUgPSBGQUxTRSkKCnNpX2RjLnBsIDwtIHNpX2RjLnByZSArCiAgZ2VvbV9wb2ludChkYXRhID0gc2lfZGMuaGlnaCAlPiUgZmlsdGVyKHJvd19udW1iZXIoKSAlJSAxMDAwID09MCksIGFlcyh4ID0gdG90YWwsIHkgPSBSLCBjb2xvciA9IGV6X2xhYmVsLCBzaGFwZSA9IGV6X2xhYmVsKSwgc2l6ZSA9IDIpICsKICBnZW9tX3BhdGgoZGF0YSA9IHNpX2RjLmhpZ2gsIGFlcyh4PSB0b3RhbCwgeSA9IFIsIGdyb3VwID0gZXpfbGFiZWwsIGNvbG9yID0gZXpfbGFiZWwpLCBzaXplID0gMSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCAiIzQ1NzViNCIsICIjZmM4ZDU5IiwgIiNmZGNiNDQiLCAiIzkxYmZkYiIpKSAgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44NSwgMC44KSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLCAKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMC4xKSkpCgpgYGAKCiMtLS0tLS0tLS0tIGNvLWluZmVjdGlvbiBtb25vY3VlIC0tLS0tLS0tLS0tLS0jCmBgYHtyfQojIGdldCByZWxldmVudCB2YXJpYWJsZXMKY2lfZGMuZGYgPC0gY2lfZHluLmRmICU+JSAKICBmaWx0ZXIodmFyaWFibGUgPT0gIkkxIiB8IHZhcmlhYmxlID09ICJJZzEiIHwgdmFyaWFibGUgPT0gIlIiKQoKIyBtb3JwaCBpbnRvIHNraW5ueSBmb3JtYXQKY2lfZGMuZGYgPC0gdGlkeXI6OnBpdm90X3dpZGVyKGNpX2RjLmRmLCBuYW1lc19mcm9tID0gdmFyaWFibGUsIHZhbHVlc19mcm9tID0gdmFsdWUsIGlkX2NvbHMgPSBjKHRpbWUsIGxhYmVsKSkgJT4lIAogIG11dGF0ZSh0b3RhbCA9IEkxK0lnMSkKCiMgZ29vZCBjdWUgYmFkIGN1ZQpjaV9jdWUuZHYgPC0gY2lfZml0bmVzcy5kZiAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gY2FzZV93aGVuKAogICAgdmFsdWUgPiAyLjI1IH4gIkhpZ2gtcGVyZm9ybWluZyIsCiAgICB2YWx1ZSA8PSAyLjI1IH4gIlBvb3ItcGVyZm9ybWluZyIKICApKQoKIyBqb2luIHdpdGggY2xhc3NpZmljYWl0b24KY2lfZGMuZGYyIDwtIGNpX2RjLmRmICU+JSBsZWZ0X2pvaW4oY2lfY3VlLmR2LCBieSA9ICJsYWJlbCIpCgojIHNwbGl0IGludG8gdG9wIGVyZm9ybWluZyBhbmQgcG9vci1wZXJmb3JtaW5nIGN1ZXMKY2lfZGMuaGlnaCA8LSBjaV9kYy5kZjIgJT4lIGZpbHRlcihjbGFzc2lmaWNhdGlvbiA9PSAiSGlnaC1wZXJmb3JtaW5nIikKY2lfZGMucG9vciA8LSBjaV9kYy5kZjIgJT4lIGZpbHRlcihjbGFzc2lmaWNhdGlvbiA9PSAiUG9vci1wZXJmb3JtaW5nIikKCiMgam9pbiBoaWdoIHBlcmZvcm1pbmcgd2l0aCBsYWJlbApjaV9kYy5oaWdoMiA8LSBjaV9kYy5oaWdoICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gYygibGFiZWwiID0gImxhYmVsX2NpIikpCgojd3JpdGVfcGFycXVldChjaV9kYy5oaWdoMiwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2NpX2RjX2hpZ2gucGFycXVldCIpKQojd3JpdGVfcGFycXVldChjaV9kYy5wb29yLCBoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvY2lfZGNfcG9vci5wYXJxdWV0IikpCmBgYAoKIyBwbG90CmBgYHtyfQpjaV9kYy5wb29yIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvY2lfZGNfcG9vci5wYXJxdWV0IikpCmNpX2RjLmhpZ2gyIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvY2lfZGNfaGlnaC5wYXJxdWV0IikpCgojIHBsb3QKY2lfZGMucHJlIDwtIGdncGxvdCgpICsKICBnZW9tX3BhdGgoZGF0YSA9IGNpX2RjLnBvb3IsIGFlcyh4PSB0b3RhbCwgeSA9IFIsIGdyb3VwID0gbGFiZWwpLCBjb2xvciA9ICJkYXJrIGdyZXkiLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICBsYWJzKGNvbG9yID0gIkNvLWluZmVjdGlvblxuaGlnaC1wZXJmb3JtaW5nIGN1ZXMiLCB4ID0gIkFzZXh1YWwgJiBzZXh1YWwgaVJCQyIsIHkgPSAiUkJDIikgKwogIHRoZW1lX2J3KCkrIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUsIGFjY3VyYWN5ID0gMC4xKSkgKwogIGd1aWRlcyhzaGFwZSA9IEZBTFNFKQoKY2lfZGMucGwgPC0gY2lfZGMucHJlICsKICBnZW9tX3BvaW50KGRhdGEgPSBjaV9kYy5oaWdoMiAlPiUgZmlsdGVyKHJvd19udW1iZXIoKSAlJSAxMDAwID09MCksIGFlcyh4ID0gdG90YWwsIHkgPSBSLCBjb2xvciA9IGV6X2xhYmVsLCBzaGFwZSA9IGV6X2xhYmVsKSwgc2l6ZSA9IDIpICsKICBnZW9tX3BhdGgoZGF0YSA9IGNpX2RjLmhpZ2gyLCBhZXMoeD0gdG90YWwsIHkgPSBSLCBncm91cCA9IGV6X2xhYmVsLCBjb2xvciA9IGV6X2xhYmVsKSwgc2l6ZSA9IDEsIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyggIiM0NTc1YjQiLCAiI2ZjOGQ1OSIsICIjZmRjYjQ0IiwgIiM5MWJmZGIiKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LCAwLjgpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksIAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAwLjEpKSkKYGBgCgojLS0tLS0tLS0tIGR1YWwgY3VlIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIwojIHByb2Nlc3MgZGF0YQpgYGB7cn0KIyB0dXJuIHNraW5ueQpkdWFsX2RjLmRmIDwtIGR1YWxfZHluLmRmICU+JSAKICBtdXRhdGUobGFiZWxfYWx0ID0gcGFzdGUobGFiZWwsICIrIiAsIGxhYmVsX2IpKSAlPiUgCiAgc2VsZWN0KGxhYmVsX2FsdCwgdGltZSwgdmFyaWFibGUsIHZhbHVlKSAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJJIiB8IHZhcmlhYmxlID09ICJJZyIgfCB2YXJpYWJsZSA9PSAiUiIpICU+JSAKICBkaXN0aW5jdChsYWJlbF9hbHQsIHRpbWUsIHZhcmlhYmxlLCAua2VlcF9hbGwgPSBUKQoKZHVhbF9kYy5kZjIgPC0gZHVhbF9kYy5kZiAlPiUgCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB2YXJpYWJsZSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSwgaWRfY29scyA9IGModGltZSwgbGFiZWxfYWx0KSkgJT4lCiAgbXV0YXRlKHRvdGFsID0gSStJZykKCndyaXRlX3BhcnF1ZXQoZHVhbF9kYy5kZjIsIGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9kdWFsX2RjLnBhcnF1ZXQiKSkKCiMgZ29vZCBkdWFsIGN1ZSAtPiBsaXN0IG9mIGdvb2QgcGVyZm9ybWluZyBkdWFsIGN1ZXMgdGhhdCBlbmNvbXBhc3Mgd2lkZSB2YXJpZXR5IG9mIGN1ZXMKc2VsZWN0ZWRfZHVhbF9jdWUgPC0gYygiUiBsb2cgKyBJIGxvZyIsICJSICsgSWcgbG9nIiwgIkcgbG9nICsgSSBsb2ciLCAiRyBsb2cgKyBJZyBsb2ciLCAiSWcgKyBJIGxvZyIpCmJhZF9kdWFsX2N1ZSA8LSBjKCJHICsgSSIsICJSICsgSWciLCAiUiBsb2cgKyBJZyIsICJHICsgUiIsICJHICsgUiBsb2ciLCAiRyArIElnIiwgIklnICsgSSIsICJSICsgSSIsICJSIGxvZyArIEkiKQoKIyBnZXQgY2xhc3NpZmljYXRpb24gLT4gUiBsb2cxMCArIEkgbG9nMTAgYXMgdGhlIG9ubHkgZ29vZCBvbmUKZHVhbF9kYy5oaWdoIDwtIGR1YWxfZGMuZGYyICU+JSBmaWx0ZXIobGFiZWxfYWx0ICVpbiUgc2VsZWN0ZWRfZHVhbF9jdWUpICU+JSAKICBtdXRhdGUobGFiZWxfYWx0ID0gZ3N1YigibG9nIiwgImxvZzEwIiwgbGFiZWxfYWx0KSkKZHVhbF9kYy5wb29yIDwtIGR1YWxfZGMuZGYyICU+JSBmaWx0ZXIobGFiZWxfYWx0ICVpbiUgYmFkX2R1YWxfY3VlKSAlPiUgCiAgbXV0YXRlKGxhYmVsX2FsdCA9IGdzdWIoImxvZyIsICJsb2cxMCIsIGxhYmVsX2FsdCkpCiN3cml0ZV9wYXJxdWV0KGR1YWxfZGMuaGlnaCwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2R1YWxfZGNfaGlnaC5wYXJxdWV0IikpCiN3cml0ZV9wYXJxdWV0KGR1YWxfZGMucG9vciwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2R1YWxfZGNfcG9vci5wYXJxdWV0IikpCgpgYGAKCiMgcGxvdApgYGB7cn0KZHVhbF9kYy5oaWdoIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvZHVhbF9kY19oaWdoLnBhcnF1ZXQiKSkKZHVhbF9kYy5wb29yIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvZHVhbF9kY19wb29yLnBhcnF1ZXQiKSkKCgpkdWFsX2RjLnByZSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBkdWFsX2RjLnBvb3IsIGFlcyh4PSB0b3RhbCwgeSA9IFIsIGdyb3VwID0gbGFiZWxfYWx0KSwgY29sb3IgPSAiZGFyayBncmV5IiwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgbGFicyhjb2xvciA9ICJIaWdoLXBlcmZvcm1pbmdcbmR1YWwgY3VlcyIsIHggPSAiQXNleHVhbCAmIHNleHVhbCBpUkJDIiwgeSA9ICJSQkMiKSArCiAgdGhlbWVfYncoKSsgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSwgYWNjdXJhY3kgPSAwLjEpKSArCiAgZ3VpZGVzKHNoYXBlID0gRkFMU0UpCgpkdWFsX2RjLnBsIDwtIGR1YWxfZGMucHJlICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX2RjLmhpZ2ggJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAwMCA9PTApLCBhZXMoeCA9IHRvdGFsLCB5ID0gUiwgY29sb3IgPSBsYWJlbF9hbHQsIHNoYXBlID0gbGFiZWxfYWx0KSwgc2l6ZSA9IDIpICsKICBnZW9tX3BhdGgoZGF0YSA9IGR1YWxfZGMuaGlnaCwgYWVzKHg9IHRvdGFsLCB5ID0gUiwgZ3JvdXAgPSBsYWJlbF9hbHQsIGNvbG9yID0gbGFiZWxfYWx0KSwgc2l6ZSA9IDEsIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyggIiM0NTc1YjQiLCAiI2ZjOGQ1OSIsICIjZmRjYjQ0IiwgIiM5MWJmZGIiLCAiYmxhY2siKSkgICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuODUsIDAuOCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwgCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDAuMSkpKQpgYGAKCiMtLS0tLS0tLS0gY28taW5mZWN0aW9uIHN0YXRpYyAtLS0tLS0tLS0tLS0tLS0tIwpgYGB7cn0KIyBpbXBvcnQgaW4gZHluYW1pY3MgZGF0YQpzdGF0aWNfZHluLmxzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvY2lfc3RhdGljLyIpLCBwYXR0ZXJuID0gIioucGFycXVldCIsIGZ1bGwubmFtZXMgPSBUKQpzdGF0aWNfZHluLmxzIDwtIGxhcHBseShzdGF0aWNfZHluLmxzLCByZWFkX3BhcnF1ZXQpCgojIGZpbHRlciB2YXJpYWJsZSBhbmQgdHJhbnNmb3JtCnN0YXRpY19keW4ubHMyIDwtIG1jbGFwcGx5KHN0YXRpY19keW4ubHMsIGZ1bmN0aW9uKHgpewogIHggJT4lIAogICAgZmlsdGVyKHZhcmlhYmxlID09ICJJMSIgfCB2YXJpYWJsZSA9PSAiSWcxIiB8IHZhcmlhYmxlID09ICJJMiIgfCB2YXJpYWJsZSA9PSAiSWcyIiB8IHZhcmlhYmxlID09ICJSIikgJT4lIAogICAgbXV0YXRlKGlkX2FsdCA9IHBhc3RlKGlkXzEsIGlkXzIpKSAlPiUgCiAgICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHZhcmlhYmxlLCB2YWx1ZXNfZnJvbSA9IHZhbHVlLCBpZF9jb2xzID0gYyh0aW1lLCBpZF9hbHQpKSAlPiUKICBtdXRhdGUodG90YWwxID0gSTErSWcxLCB0b3RhbDIgPSBJMitJZzIpCn0pCgpzdGF0aWNfZGMuZGYgPC0gZG8uY2FsbChyYmluZCwgc3RhdGljX2R5bi5sczIpCnN0YXRpY19kYy5kZiA8LSBzdGF0aWNfZGMuZGYgJT4lIAogIG11dGF0ZShpZF8xID0gZ3N1YigiIC4qIiwgIiIsIGlkX2FsdCksCiAgICAgICAgIGlkXzIgPSBnc3ViKCIuKiAiLCAiIiwgaWRfYWx0KSkgJT4lIAogIGZpbHRlcihpZF8xICE9IGlkXzIpCiN3cml0ZV9wYXJxdWV0KHN0YXRpY19kYy5kZiwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL3N0YXRpY19kYy5wYXJxdWV0IikpCmBgYAoKIyBmdXJ0aGVyIHByb2Nlc3NpbmcKYGBge3J9CnN0YXRpY19kYy5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL3N0YXRpY19kYy5wYXJxdWV0IikpCiMgZ2V0IHdpbm5lcnMgYW5kIGxvc2VycwojIyBpbXBvcnQgaW4gZml0bmVzcwpzdGF0aWNfZml0bmVzcy5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX3N0YXRpYy5jc3YiKSkKIyMgZ2V0IHdpbm5lciBzaXR1YXRpb24Kc3RhdGljX2ZpdG5lc3MuZGYyIDwtIHN0YXRpY19maXRuZXNzLmRmICU+JSAKICBmaWx0ZXIoaWRfMSAhPSBpZF8yKSAlPiUgCiAgbXV0YXRlKHdpbm5pbmdfaWQgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzX2RpZmZlcmVuY2UgPiAwIH4gaWRfMSwKICAgIGZpdG5lc3NfZGlmZmVyZW5jZTwgMCB+IGlkXzIKICApLAogIGxvc2luZ19pZCA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3NfZGlmZmVyZW5jZSA8IDAgfiBpZF8xLAogICAgZml0bmVzc19kaWZmZXJlbmNlPiAwIH4gaWRfMgogICkpCgojIGxlZnQgam9pbgpzdGF0aWNfZGMuZGYyIDwtIHN0YXRpY19kYy5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChzdGF0aWNfZml0bmVzcy5kZjIsIGlkXzEsIGlkXzIsIHdpbm5pbmdfaWQsIGxvc2luZ19pZCwgZml0bmVzc19kaWZmZXJlbmNlKSwgYnkgPSBjKCJpZF8xIiwgImlkXzIiKSkKCiMgZ2V0IHdpbm5lci1sb3NlciBkaWZmZXJlbmNlIGluIHRlcm1zIG9mIEkrSWcgYWxzbyBmaWx0ZXIgb3V0IHRvIG9ueWwgdmVyeSBzdHJvbmcgZml0bmVzcyBkaWZmZXJlbmNlCnN0YXRpY19kYy5kZjMgPC0gc3RhdGljX2RjLmRmMiAlPiUgCiAgbXV0YXRlKHRvdGFsX2RpZmYgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzX2RpZmZlcmVuY2UgPiAwIH4gdG90YWwxLXRvdGFsMiwKICAgIGZpdG5lc3NfZGlmZmVyZW5jZTwgMCB+IHRvdGFsMi10b3RhbDIKICApLAogIHRvdGFsX3dpbm5lciA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3NfZGlmZmVyZW5jZSA+IDAgfiB0b3RhbDEsCiAgICBmaXRuZXNzX2RpZmZlcmVuY2U8IDAgfiB0b3RhbDIKICApLAogIHRvdGFsX2xvc2VyID0gY2FzZV93aGVuKAogICAgZml0bmVzc19kaWZmZXJlbmNlID4gMCB+IHRvdGFsMiwKICAgIGZpdG5lc3NfZGlmZmVyZW5jZTwgMCB+IHRvdGFsMQogICkpICU+JSAKICBmaWx0ZXIoYWJzKGZpdG5lc3NfZGlmZmVyZW5jZSkgPiAwLjUpCmBgYAoKIyBwbG90CmBgYHtyfQpzdGF0aWNfZGMucGwgPC0gZ2dwbG90KCkgKwogIGdlb21fcGF0aChkYXRhID0gc3RhdGljX2RjLmRmMywgYWVzKHg9IHRvdGFsX3dpbm5lciwgeSA9IFIsIGdyb3VwID0gaWRfYWx0LCBjb2xvciA9ICJXaW5uZXIiKSwgYWxwaGEgPSAwLjUsIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIGdlb21fcGF0aChkYXRhID0gc3RhdGljX2RjLmRmMywgYWVzKHg9IHRvdGFsX2xvc2VyLCB5ID0gUiwgZ3JvdXAgPSBpZF9hbHQsIGNvbG9yID0gIkxvc2VyIiksCiAgICAgICAgICBhbHBoYSA9IDAuNSxhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICBsYWJzKGNvbG9yID0gIlN0YXR1cyIsIHggPSAiQXNleHVhbCAmIHNleHVhbCBpUkJDIiwgeSA9ICJSQkMiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJXaW5uZXIiID0gIiM0NTc1YjQiLCJMb3NlciI9ICIjZmM4ZDU5IikpICArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUsIGFjY3VyYWN5ID0gMC4xKSkKYGBgCgoKIy0tLS0tLS0tLWNvLWluZmVjdGlvbiBpbnZhc2lvbiAtLS0tLS0tLS0tLS0tLS0jCiMgZ2V0IGludmFzaW9uIGR5bmFtaWMKYGBge3J9CiMgZ2V0IGludmFzaW9uIGRmCmludmFzaW9uX2ZpdG5lc3MuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9pbnZhc2lvbi5jc3YiKSkKCiMgZ2V0IGN1ZSByYW5nZQpjaV9jdWVfcmFuZ2UgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jdWVfcmFuZ2VfY2kuY3N2IikpCmludmFzaW9uX2ZpdG5lc3MuZGYyIDwtIGludmFzaW9uX2ZpdG5lc3MuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoY2lfY3VlX3JhbmdlLCBpZCwgbXV0X2N1ZSA9IGN1ZSwgbXV0X2xvdyA9IGxvdywgbXV0X2hpZ2ggPSBoaWdoLCBtdXRfYnkgPSBieSksIGJ5ID0gYygibXV0X2lkIj0gImlkIikpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGNpX2N1ZV9yYW5nZSwgaWQsIHJlc19jdWUgPSBjdWUsIHJlc19sb3cgPSBsb3csIHJlc19oaWdoID0gaGlnaCwgcmVzX2J5ID0gYnkpLCBieSA9IGMoInJlc19pZCI9ICJpZCIpKQpgYGAKCiMgZnVuY3Rpb24gdG8gZ2V0IGR5bmFtaWMKYGBge3J9CmdldF9pbnZhc2lvbl9keW4gPC0gZnVuY3Rpb24oZGYpewogICMgZ2V0IGN1ZXMKICBtdXRfY3VlIDwtIGRmJG11dF9jdWUKICByZXNfY3VlIDwtIGRmJHJlc19jdWUKICAKICAjIGdldCBpbmZvIG9mIGN1ZXMgKGZvciBjbyBpbmZlY3Rpb24pCiAgaWYoc3RyaW5ncjo6c3RyX2RldGVjdChtdXRfY3VlLCAiLWkiKSl7bXV0X2N1ZSA9IGdzdWIoIiotaSIsICIxIiwgbXV0X2N1ZSl9CiAgaWYoc3RyaW5ncjo6c3RyX2RldGVjdChtdXRfY3VlLCAiLWkiLCBuZWdhdGUgPSBUKSl7bXV0X2N1ZSA9IG11dF9jdWV9CiAgaWYoc3RyaW5ncjo6c3RyX2RldGVjdChyZXNfY3VlLCAiLWkiKSl7cmVzX2N1ZSA9IGdzdWIoIiotaSIsICIyIiwgcmVzX2N1ZSl9CiAgaWYoc3RyaW5ncjo6c3RyX2RldGVjdChyZXNfY3VlLCAiLWkiLCBuZWdhdGUgPSBUKSl7cmVzX2N1ZSA9IHJlc19jdWV9CiAgCiAgIyBnZXQgbG9nCiAgbXV0X2xvZyA8LSBpZmVsc2Uoc3RyaW5ncjo6c3RyX2RldGVjdChkZiRtdXRfaWQsICJsb2ciKSwgImxvZzEwIiwgIm5vbmUiKQogIHJlc19sb2cgPC0gaWZlbHNlKHN0cmluZ3I6OnN0cl9kZXRlY3QoZGYkcmVzX2lkLCAibG9nIiksICJsb2cxMCIsICJub25lIikKICAKICAjIGdldCBwYXJhbWV0ZXJzCiAgbXV0X3BhciA8LSBjKGRmJG11dF92YXIxX29wdCwgZGYkbXV0X3ZhcjJfb3B0LCBkZiRtdXRfdmFyM19vcHQsIGRmJG11dF92YXI0X29wdCkKICByZXNfcGFyIDwtIGMoZGYkcmVzX3ZhcjEsIGRmJHJlc192YXIyLCBkZiRyZXNfdmFyMywgZGYkcmVzX3ZhcjQpCiAgCiAgIyBnZXQgY3VlIHJhbmdlCiAgbXV0X2N1ZV9yYW5nZSA8LSBzZXEoZGYkbXV0X2xvdywgZGYkbXV0X2hpZ2gsIGJ5ID0gZGYkbXV0X2J5KQogIHJlc19jdWVfcmFuZ2UgPC0gc2VxKGRmJHJlc19sb3csIGRmJHJlc19oaWdoLCBieSA9IGRmJHJlc19ieSkKICAKICAjIGdldCBkeW5hbWljcyBvZiBjbyBpbmZlY3Rpb24KICBjaV9keW4gPC0gY2hhYmF1ZGlfY2lfY2xlYW4oCiAgICBwYXJhbWV0ZXJzX2NyXzEgPSBtdXRfcGFyLAogICAgcGFyYW1ldGVyc19jcl8yID0gcmVzX3BhciwKICAgICAgICAgICAgICAgICAgaW1tdW5pdHkgPSAidHN1a3VzaGkiLAogICAgICAgICAgICAgICAgICBwYXJhbWV0ZXJzID0gcGFyYW1ldGVyc190c3VrdXNoaSwKICAgICAgICAgICAgICAgICAgY3VlXzEgPSBtdXRfY3VlLAogICAgICAgICAgICAgICAgICBjdWVfMiA9IHJlc19jdWUsCiAgICAgICAgICAgICAgICAgIGN1ZV9yYW5nZV8xID0gbXV0X2N1ZV9yYW5nZSwKICAgICAgICAgICAgICAgICBjdWVfcmFuZ2VfMiA9IHJlc19jdWVfcmFuZ2UsCiAgICAgICAgICAgICAgICBsb2dfY3VlXzEgPSBtdXRfbG9nLAogICAgICAgICAgICAgICAgbG9nX2N1ZV8yID0gcmVzX2xvZywKICAgICAgICAgICAgICAgIHNvbHZlciA9ICJ2b2RlIiwKICAgICAgICAgICAgICAgIHRpbWVfcmFuZ2UgPSBzZXEoMCwgMzAsIDAuMDAxKSwKICAgIGR5biA9IFQpCiAgCiAgIyBhcHBlbmQgbGFiZWwgdG8gYWxsIGRmCiBjaV9keW4yIDwtIGNiaW5kKGNpX2R5biwgbXV0X2lkID0gZGYkbXV0X2lkLCByZXNfaWQgPSBkZiRyZXNfaWQpCiAgCiAgIyB3cml0ZQogd3JpdGVfcGFycXVldChjaV9keW4yLCBwYXN0ZTAoaGVyZSgiZGF0YS9jaV9pbnZhc2lvbl9keW4vIiksIGRmJG11dF9pZCwgIi0iLCBkZiRyZXNfaWQsICIucGFycXVldCIpKQp9CmBgYAoKCiMgcnVuIGR5bmFtaWMgZnVuY2l0b24KYGBge3J9CiMgZ2V0IGZ1bmN0aW9uIGFuZCBwYXJhbWV0ZXJzCnNvdXJjZShoZXJlKCJmdW5jdGlvbnMvY2hhYmF1ZGlfY2lfY2xlYW4uUiIpKQpwYXJhbWV0ZXJzX3RzdWt1c2hpIDwtIGMoUjEgPSA4Ljg5KigxMF42KSwgIyBzbGlnaHRseSBoaWdoZXIKICAgICAgICAgICAgICAgIGxhbWJkYSA9IDMuNyooMTBeNSksCiAgICAgICAgICAgICAgICBtdSA9IDAuMDI1LCAKICAgICAgICAgICAgICAgIHAgPSA4KigxMF4tNiksICMgZG91YmxlZCBmb3JtIG9yaWdpbmFsCiAgICAgICAgICAgICAgICBhbHBoYSA9IDEsIAogICAgICAgICAgICAgICAgYWxwaGFnID0gMiwgCiAgICAgICAgICAgICAgICBiZXRhID0gNS43MjEsIAogICAgICAgICAgICAgICAgbXVtID0gNDgsIAogICAgICAgICAgICAgICAgbXVnID0gNCwgCiAgICAgICAgICAgICAgICBJMCA9IDQzLjg1OTY1LCAKICAgICAgICAgICAgICAgIElnMCA9IDAsIAogICAgICAgICAgICAgICAgYSA9IDE1MCwgCiAgICAgICAgICAgICAgICBiID0gMTAwLCAKICAgICAgICAgICAgICAgIHNwID0gMSwKICAgICAgICAgICAgICAgIHBzaW4gPSAxNi42OTIzNCwKICAgICAgICAgICAgICAgIHBzaXcgPSAwLjg0MzE3ODUsCiAgICAgICAgICAgICAgICBwaGluID0gMC4wMzUyMDU5MSwgCiAgICAgICAgICAgICAgICBwaGl3ID0gNTUwLjg0MiwKICAgICAgICAgICAgICAgIGlvdGEgPSAyLjE4KigxMF42KSwKICAgICAgICAgICAgICAgIHJobyA9IDAuMjYyNzE1NikKIyBzcGxpdAppbnZhc2lvbi5scyA8LSBzcGxpdChpbnZhc2lvbl9maXRuZXNzLmRmMiwgc2VxKG5yb3coaW52YXNpb25fZml0bmVzcy5kZjIpKSkKCiMgcnVuIGZ1bmN0aW9uCm1jbGFwcGx5KGludmFzaW9uLmxzLCBnZXRfaW52YXNpb25fZHluLCBtYy5jb3JlcyA9IDQpCmBgYAoKCiMgcHJvY2VzcyBkYXRhCmBgYHtyfQojIGltcG9ydCBpbiBpbnZhc2lvbiBkeW5hbWljcwppbnZhc2lvbl9keW4ubHMgPC0gbGlzdC5maWxlcyhwYXRoID0gaGVyZSgiZGF0YS9jaV9pbnZhc2lvbl9keW4iKSwgcGF0dGVybiA9ICIqLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKaW52YXNpb25fZHluLmxzIDwtIGxhcHBseShpbnZhc2lvbl9keW4ubHMsIHJlYWRfcGFycXVldCkKCiMgZmlsdGVyIGFuZCBzbyBvbgppbnZhc2lvbl9keW4ubHMyIDwtIG1jbGFwcGx5KGludmFzaW9uX2R5bi5sc1sxNjc6MTc3XSwgbWMuY29yZXMgPSA0LCBmdW5jdGlvbih4KXsKICB4MiA8LSB4ICU+JSAKICAgIGZpbHRlcih2YXJpYWJsZSA9PSAiSTEiIHwgdmFyaWFibGUgPT0gIklnMSIgfCB2YXJpYWJsZSA9PSAiSTIiIHwgdmFyaWFibGUgPT0gIklnMiIgfCB2YXJpYWJsZSA9PSAiUiIpICU+JSAKICAgIG11dGF0ZShpZF9hbHQgPSBwYXN0ZShtdXRfaWQsIHJlc19pZCkpICU+JSAKICAgIHNlbGVjdChpZF9hbHQsIHRpbWUsIHZhcmlhYmxlLCB2YWx1ZSkgJT4lIAogICAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB2YXJpYWJsZSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSwgaWRfY29scyA9IGModGltZSwgaWRfYWx0KSkgJT4lCiAgbXV0YXRlKHRvdGFsMSA9IEkxK0lnMSwgdG90YWwyID0gSTIrSWcyKQogIAogIHdyaXRlX3BhcnF1ZXQoeDIsIHBhc3RlMChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvY2lfaW52YXNpb24vIiksIHVuaXF1ZSh4MiRpZF9hbHQpLCAiX2RjLnBhcnF1ZXQiKSkKfSkKCiMgZmV0Y2ggZGF0YQppbnZhc2lvbl9keW4ubHMyIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9jaV9pbnZhc2lvbiIpLCBwYXR0ZXJuID0gIioucGFycXVldCIsIGZ1bGwubmFtZXMgPSBUKQppbnZhc2lvbl9keW4ubHMyIDwtIGxhcHBseShpbnZhc2lvbl9keW4ubHMyLCByZWFkX3BhcnF1ZXQpCmludmFzaW9uX2RjLmRmIDwtIGRvLmNhbGwocmJpbmQsIGludmFzaW9uX2R5bi5sczIpCmludmFzaW9uX2RjLmRmIDwtIGludmFzaW9uX2RjLmRmICU+JSAKICBtdXRhdGUobXV0X2lkID0gZ3N1YigiIC4qIiwgIiIsIGlkX2FsdCksCiAgICAgICAgIHJlc19pZCA9IGdzdWIoIi4qICIsICIiLCBpZF9hbHQpKSAlPiUgCiAgZmlsdGVyKG11dF9pZCAhPSByZXNfaWQpCiN3cml0ZV9wYXJxdWV0KGludmFzaW9uX2RjLmRmLCBoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvaW52YXNpb25fZGMucGFycXVldCIpKQpgYGAKCiMgZnVydGhlciBwcm9jZXNzaW5nCmBgYHtyfQppbnZhc2lvbl9kYy5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2ludmFzaW9uX2RjLnBhcnF1ZXQiKSkKIyBnZXQgd2lubmVycyBhbmQgbG9zZXJzCmludmFzaW9uX2ZpdG5lc3MuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9pbnZhc2lvbi5jc3YiKSkKaW52YXNpb25fZGMuZGYyIDwtIGludmFzaW9uX2RjLmRmICU+JSAKICBsZWZ0X2pvaW4oaW52YXNpb25fZml0bmVzcy5kZiwgYnkgPSBjKCJtdXRfaWQiLCAicmVzX2lkIikpICU+JSAKICBtdXRhdGUoCiAgdG90YWxfd2lubmVyID0gY2FzZV93aGVuKAogICAgZml0bmVzcz4gMCB+IHRvdGFsMSwKICAgIGZpdG5lc3M8IDAgfiB0b3RhbDIKICApLAogIHRvdGFsX2xvc2VyID0gY2FzZV93aGVuKAogICAgZml0bmVzcyA+IDAgfiB0b3RhbDIsCiAgICBmaXRuZXNzIDwgMCB+IHRvdGFsMQogICkpICU+JSAKICBmaWx0ZXIoYWJzKGZpdG5lc3MpID4gMC41KQpgYGAKCiMgcGxvdApgYGB7cn0KaW52YXNpb25fZGMucGwgPC0gZ2dwbG90KCkgKwogIGdlb21fcGF0aChkYXRhID0gaW52YXNpb25fZGMuZGYyLCBhZXMoeD0gdG90YWxfd2lubmVyLCB5ID0gUiwgZ3JvdXAgPSBpZF9hbHQsIGNvbG9yID0gIldpbm5lciIpLCBhbHBoYSA9IDAuNSwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBpbnZhc2lvbl9kYy5kZjIsIGFlcyh4PSB0b3RhbF9sb3NlciwgeSA9IFIsIGdyb3VwID0gaWRfYWx0LCBjb2xvciA9ICJMb3NlciIpLAogICAgICAgICAgYWxwaGEgPSAwLjUsYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgbGFicyhjb2xvciA9ICJTdGF0dXMiLCB4ID0gIkFzZXh1YWwgJiBzZXh1YWwgaVJCQyIsIHkgPSAiUkJDIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiV2lubmVyIiA9ICIjNDU3NWI0IiwiTG9zZXIiPSAiI2ZjOGQ1OSIpKSAgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFLCBhY2N1cmFjeSA9IDAuMSkpICU+JSAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKIy0tLS0tLS0tLSBwbG90IGRpc2Vhc2UgY3VydmVzIHRvZ2V0aGVyIC0tLS0tLS0tLS0tLSMKYGBge3J9CmRjLnBsMSA8LSBnZ2FycmFuZ2Uoc2lfZGMucGwsIGNpX2RjLnBsLCBkdWFsX2RjLnBsLCBuY29sID0gMywgYWxpZ24gPSAiaCIsIGxhYmVscyA9IGMoIkEiLCAiQiIsICJDIiksIHdpZHRocyA9IGMoMS4xLCAwLjksIDEuMSkpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL2Rpc2Vhc2VfY3VydmUxLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIyNTAsIGhlaWdodCA9IDgwMCwgc2NhbGUgPSAxLjcyLCBkcGk9MzAwLCBjb21wcmVzc2lvbiA9ICJsenciKQoKZGMucGwyIDwtIGdnYXJyYW5nZShzdGF0aWNfZGMucGwsIGludmFzaW9uX2RjLnBsLCBuY29sID0gMiwgYWxpZ24gPSAiaCIsIGxhYmVscyA9IGMoIkQiLCAiRSIpLCBjb21tb24ubGVnZW5kID0gVCkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vZGlzZWFzZV9jdXJ2ZTIudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjI1MCwgaGVpZ2h0ID0gMTEwMCwgc2NhbGUgPSAxLjQsIGRwaT0zMDAsIGNvbXByZXNzaW9uID0gImx6dyIpCmBgYAoKIy0tLS0tLS0tLSBxdWFudGlmeWluZyBkaXNlYXNlIGN1cnZlIGFyZWEgLS0tLS0tLS0tLS0tIwojIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSBhcmVhIGJldHdlZW4gc2V0cyBvZiBwb2ludHMgLT4gZnJvbSBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8zNjcyMjYwL2FyZWEtY292ZXJlZC1ieS1hLXBvaW50LWNsb3VkLXdpdGgtcgpgYGB7cn0KbGlicmFyeShzcGxhbmNzKQpjaGE8LWZ1bmN0aW9uKGRmKXsKICB4IDwtIGRmJHRvdGFsCiAgeSA8LSBkZiRSCmNodWxsKHgseSktPmkKcmV0dXJuKGFyZWFwbChjYmluZCh4W2ldLHlbaV0pKSkKfQpgYGAKCiMgbG9vcCB0byBnZXQgYXJlYTogc2luZ2xlIGluZmVjdGlvbgpgYGB7cn0KIyBzcGxpdCBkZgpzaV9kY19oaWdoLmxzIDwtIHNwbGl0KHNpX2RjLmhpZ2gsIHNpX2RjLmhpZ2gkZXpfbGFiZWxfc2kpCnNpX2RjX3Bvb3IubHMgPC0gc3BsaXQoc2lfZGMucG9vciwgc2lfZGMucG9vciRpZCkKCiMgZ2V0IGFyZWEKc2lfZGNfaGlnaC5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KHNpX2RjX2hpZ2gubHMsIGNoYSkpLCBpZF9hbHQgPSBuYW1lcyhsYXBwbHkoc2lfZGNfaGlnaC5scywgY2hhKSkpCnNpX2RjX3Bvb3IuYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShzaV9kY19wb29yLmxzLCBjaGEpKSwgaWRfYWx0ID0gbmFtZXMobGFwcGx5KHNpX2RjX3Bvb3IubHMsIGNoYSkpKQoKCiMgam9pbiB3aXRoIGZpdG5lc3MKc2lfZml0bmVzcy5kZiA8LSBzaV9maXRuZXNzLmRmICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gYygiaWQiID0gImlkX3NpIikpCgpzaV9kY19oaWdoLmFyZWEyIDwtIHNpX2RjX2hpZ2guYXJlYSAlPiUgCiAgbGVmdF9qb2luKHNpX2ZpdG5lc3MuZGYsIGJ5ID0gYygiaWRfYWx0IiA9ICJlel9sYWJlbF9zaSIpKSAlPiUgCiAgc2VsZWN0KHZhbHVlLCBhcmVhKSAlPiUgCiAgbXV0YXRlKGNvbmRpdGlvbiA9ICJTaW5nbGUgaW5mZWN0aW9uIikKCnNpX2RjX3Bvb3IuYXJlYTIgPC0gc2lfZGNfcG9vci5hcmVhICU+JSAKICBsZWZ0X2pvaW4oc2lfZml0bmVzcy5kZiwgYnkgPSBjKCJpZF9hbHQiID0gImlkIikpICU+JSAKICBzZWxlY3QodmFsdWUsIGFyZWEpICU+JSAKICBtdXRhdGUoY29uZGl0aW9uID0gIlNpbmdsZSBpbmZlY3Rpb24iKQpgYGAKCiMgY29pbmZlY3Rpb24KYGBge3J9CiMgc3BsaXQKY2lfZGNfaGlnaC5scyA8LSBzcGxpdChjaV9kYy5oaWdoMiwgY2lfZGMuaGlnaDIkZXpfbGFiZWwpCmNpX2RjX3Bvb3IubHMgPC0gc3BsaXQoY2lfZGMucG9vciwgY2lfZGMucG9vciRsYWJlbCkKCiMgcnVuIGZ1bmN0aW9uIHRvIGZpbmQgYXJlYQpjaV9kY19oaWdoLmFyZWEgPC0gY2JpbmQuZGF0YS5mcmFtZShhcmVhID0gYXMubnVtZXJpYyhsYXBwbHkoY2lfZGNfaGlnaC5scywgY2hhKSksIGlkX2FsdCA9IG5hbWVzKGxhcHBseShjaV9kY19oaWdoLmxzLCBjaGEpKSwgdmFsdWUgPSB1bmlxdWUoY2lfZGMuaGlnaDIkdmFsdWUpKQoKY2lfZGNfcG9vci5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KGNpX2RjX3Bvb3IubHMsIGNoYSkpLCBpZF9hbHQgPSBuYW1lcyhsYXBwbHkoY2lfZGNfcG9vci5scywgY2hhKSksIHZhbHVlID0gdW5pcXVlKGNpX2RjLnBvb3IkdmFsdWUpKQoKIyBlZGl0IGFuZCBqb2luCmNpX2RjX2hpZ2guYXJlYTIgPC0gIGNpX2RjX2hpZ2guYXJlYSAlPiUgCiAgc2VsZWN0KGFyZWEsIHZhbHVlKSAlPiUgCiAgbXV0YXRlKGNvbmRpdGlvbiA9ICJDby1pbmZlY3Rpb24iKQoKY2lfZGNfcG9vci5hcmVhMiA8LSAgY2lfZGNfcG9vci5hcmVhICU+JSAKICBzZWxlY3QoYXJlYSwgdmFsdWUpICU+JSAKICBtdXRhdGUoY29uZGl0aW9uID0gIkNvLWluZmVjdGlvbiIpCmBgYAoKIyBkdWFsIGN1ZQpgYGB7cn0KIyBzcGxpdApkdWFsLmRjIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvZHVhbF9kYy5wYXJxdWV0IikpCmR1YWxfZGMubHMgPC0gc3BsaXQoZHVhbC5kYywgZHVhbC5kYyRsYWJlbF9hbHQpCgojIGdldCBhcmVhCmR1YWxfZGMuYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShkdWFsX2RjLmxzLCBjaGEpKSwgaWRfYWx0ID0gbmFtZXMobGFwcGx5KGR1YWxfZGMubHMsIGNoYSkpKQoKIyBiaW5kIHdpdGggZml0bmVzcwpkdWFsX2ZpdG5lc3MuZGYgPC0gZHVhbF9maXRuZXNzLmRmICU+JSBtdXRhdGUoaWRfYWx0ID0gcGFzdGUobGFiZWwsICIrIiwgbGFiZWxfYikpCmR1YWxfZGMuYXJlYTIgPC0gZHVhbF9kYy5hcmVhICU+JSAKICBsZWZ0X2pvaW4oZHVhbF9maXRuZXNzLmRmLCBieSA9ICJpZF9hbHQiKSAlPiUgCiAgc2VsZWN0KGFyZWEsIHZhbHVlKSAlPiUgCiAgbXV0YXRlKGNvbmRpdGlvbiA9ICJEdWFsLWN1ZSIpICU+JSAKICBmaWx0ZXIodmFsdWUgPiAyKQoKYGBgCgojLS0tLS0tIGdldCBmaXR0ZWQgc2NhdHRlciBwbG90IGZvciBhbGwgc2luZ2xlIGluZmVjdGlvbiwgY28gaW5mZWN0aW9uLCBhbmQgZHVhbCBjdWUgLS0tLS0tLS0jCmBgYHtyfQojIHJiaW5kIGFsbApkYy5hcmVhIDwtIHJiaW5kKHNpX2RjX2hpZ2guYXJlYTIsIHNpX2RjX3Bvb3IuYXJlYTIsIGNpX2RjX2hpZ2guYXJlYTIsIGNpX2RjX3Bvb3IuYXJlYTIsIGR1YWxfZGMuYXJlYTIpICU+JSAKICBtdXRhdGUoY29uZGl0aW9uID0gZmN0X3JlbGV2ZWwoY29uZGl0aW9uLCBjKCJTaW5nbGUgaW5mZWN0aW9uIiwgIkNvLWluZmVjdGlvbiIsICJEdWFsLWN1ZSIpKSkKCiMgcGxvdApkY19hcmVhLnBsMSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZGMuYXJlYSwgYWVzKHggPSBhcmVhLCB5ID0gdmFsdWUpKSArCiAgZmFjZXRfd3JhcCh+Y29uZGl0aW9uLCBzY2FsZXMgPSAiZnJlZSIpICsKICBnZW9tX3Ntb290aChkYXRhID0gZGMuYXJlYSwgbWV0aG9kID0gImxtIiwgYWxwaGEgPSAuMTUsIGFlcyh4ID0gYXJlYSwgeSA9IHZhbHVlKSwgY29sb3IgPSAiIzQ1NzViNCIpICsKICBsYWJzKHggPSAiQXJlYSIsIHkgPSAiRml0bmVzcyIsIGNvbG9yID0gIlN0YXR1cyIpICsKICB0aGVtZV9idygpCmBgYAoKCiMtLS0tLS0tIHBsb3QgdG9nZXRoZXIgd2l0aCBkaXNlYXNlIGN1cnZlIC0tLS0tLS0tIwpgYGB7cn0KZ2dhcnJhbmdlKHNpX2RjLnBsLCBjaV9kYy5wbCwgZHVhbF9kYy5wbCwgZGNfYXJlYS5wbDEsIGxhYmVscyA9IGMoIkEiLCAiQiIsICJDIiwgIkQiKSwgYWxpZ24gPSAiaCIsIG5jb2wgPSA0LCB3aWR0aHMgPSBjKDEsIDAuOSwgMSwgMS41KSkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vZGlzZWFzZV9jdXJ2ZTEudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjI1MCwgaGVpZ2h0ID0gNjAwLCBzY2FsZSA9IDIuNSwgZHBpPTMwMCwgY29tcHJlc3Npb24gPSAibHp3IikKYGBgCgoKIy0tLS0tLS0tLSBzdGF0aWMgYXJlYSBjb21wYXJpc29uIC0tLS0tLS0tLS0tLS0jCiMgY29tcHV0ZSBhcmVhCmBgYHtyfQojIGltcG9ydCBpbiBkYyBkeW5hbWljIGFuZCBmaXRuZXNzCnN0YXRpY19kYy5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL3N0YXRpY19kYy5wYXJxdWV0IikpCnN0YXRpY19maXRuZXNzLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY2lfc3RhdGljLmNzdiIpKQoKIyBnZXQgd2lubmVyIGFuZCBsb3NlcgpzdGF0aWNfZGMuZGY0IDwtIHN0YXRpY19kYy5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChzdGF0aWNfZml0bmVzcy5kZiwgaWRfMSwgaWRfMiwgZml0bmVzc19kaWZmZXJlbmNlKSwgYnkgPSBjKCJpZF8xIiwgImlkXzIiKSkgJT4lCiAgZmlsdGVyKGlkXzEgIT0gaWRfMikgJT4lIAogIG11dGF0ZSgKICB0b3RhbF93aW5uZXIgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzX2RpZmZlcmVuY2UgPiAwIH4gdG90YWwxLAogICAgZml0bmVzc19kaWZmZXJlbmNlPCAwIH4gdG90YWwyCiAgKSwKICB0b3RhbF9sb3NlciA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3NfZGlmZmVyZW5jZSA+IDAgfiB0b3RhbDIsCiAgICBmaXRuZXNzX2RpZmZlcmVuY2U8IDAgfiB0b3RhbDEKICApKSU+JSAKICBmaWx0ZXIoYWJzKGZpdG5lc3NfZGlmZmVyZW5jZSkgPiAwLjUpCgojIHNwbGl0IGJ5IHdpbm5lciBhbmQgbG9zZXIKc3RhdGljX2RjLmxzMSA8LSBzcGxpdChzZWxlY3Qoc3RhdGljX2RjLmRmNCwgUiwgdG90YWwgPSB0b3RhbF93aW5uZXIpLCBzdGF0aWNfZGMuZGY0JGlkX2FsdCkKc3RhdGljX2RjLmxzMiA8LSBzcGxpdChzZWxlY3Qoc3RhdGljX2RjLmRmNCwgUiwgdG90YWwgPSB0b3RhbF9sb3NlciksIHN0YXRpY19kYy5kZjQkaWRfYWx0KQoKIyBnZXQgYXJlYQpzdGF0aWNfd2luLmFyZWEgPC0gY2JpbmQuZGF0YS5mcmFtZShhcmVhID0gYXMubnVtZXJpYyhsYXBwbHkoc3RhdGljX2RjLmxzMSwgY2hhKSksIHN0YXR1cyA9ICJXaW5uZXIiKQpzdGF0aWNfbG9zZXIuYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShzdGF0aWNfZGMubHMyLCBjaGEpKSwgc3RhdHVzID0gIkxvc2VyIikKCiMgcGFpcgpzdGF0aWMuYXJlYSA8LSBjYmluZChzZWxlY3Qoc3RhdGljX3dpbi5hcmVhLCBXaW5uZXIgPSBhcmVhKSwKICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHN0YXRpY19sb3Nlci5hcmVhLCBMb3NlciA9IGFyZWEpKSAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gaWZlbHNlKFdpbm5lcj5Mb3NlciwgIldpbm5lciBsYXJnZXIgYXJlYSIsICJMb3NlciBsYXJnZXIgYXJlYSIpKQpgYGAKCiMgcGxvdCBzdGF0aWMKYGBge3J9CnN0YXRpY19hcmVhLnBsIDwtIGdncGFpcmVkKHN0YXRpYy5hcmVhLCBjb25kMSA9ICJXaW5uZXIiLCBjb25kMiA9ICJMb3NlciIsIGxpbmUuY29sb3IgPSAiY2xhc3NpZmljYXRpb24iLCBhbHBoYSA9IDAuMikgKwogIGxhYnMoeCA9ICJTdGF0dXMiLCB5ID0gIkFyZWEiLCBjb2xvciA9ICJDb21wYXJpc29uIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJMb3NlciBsYXJnZXIgYXJlYSIgPSAiI2ZjOGQ1OSIsICJXaW5uZXIgbGFyZ2VyIGFyZWEiID0gIiM0NTc1YjQiKSkgKwogIHN0YXRfY29tcGFyZV9tZWFucyhwYWlyZWQgPSBUUlVFLCBoanVzdCA9IC0wLjMpCmBgYAoKCiMtLS0tLS0tLS0gaW52YXNpb24gYXJlYSBjb21wYXJpc29uIC0tLS0tLS0tLS0tLS0tLS0tIwojIGdldCBhcmVhCmBgYHtyfQojIGltcG9ydCBpbiBkYyBkeW5hbWljIGFuZCBmaXRuZXNzCmludmFzaW9uX2RjLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvaW52YXNpb25fZGMucGFycXVldCIpKQppbnZhc2lvbl9maXRuZXNzLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY2lfaW52YXNpb24uY3N2IikpCgppbnZhc2lvbl9kYy5kZjQgPC0gaW52YXNpb25fZGMuZGYgJT4lIAogIGxlZnRfam9pbihpbnZhc2lvbl9maXRuZXNzLmRmLCBieSA9IGMoIm11dF9pZCIsICJyZXNfaWQiKSkgJT4lIAogIG11dGF0ZSgKICB0b3RhbF93aW5uZXIgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzPiAwIH4gdG90YWwxLAogICAgZml0bmVzczwgMCB+IHRvdGFsMgogICksCiAgdG90YWxfbG9zZXIgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzID4gMCB+IHRvdGFsMiwKICAgIGZpdG5lc3MgPCAwIH4gdG90YWwxCiAgKSkgJT4lIAogIGZpbHRlcihhYnMoZml0bmVzcykgPiAwLjUpCgojIHNwbGl0IGJ5IHdpbm5lciBhbmQgbG9zZXIKaW52YXNpb25fZGMubHMxIDwtIHNwbGl0KHNlbGVjdChpbnZhc2lvbl9kYy5kZjQsIFIsIHRvdGFsID0gdG90YWxfd2lubmVyKSwgaW52YXNpb25fZGMuZGY0JGlkX2FsdCkKaW52YXNpb25fZGMubHMyIDwtIHNwbGl0KHNlbGVjdChpbnZhc2lvbl9kYy5kZjQsIFIsIHRvdGFsID0gdG90YWxfbG9zZXIpLCBpbnZhc2lvbl9kYy5kZjQkaWRfYWx0KQoKIyBnZXQgYXJlYQppbnZhc2lvbl93aW4uYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShpbnZhc2lvbl9kYy5sczEsIGNoYSkpLCBzdGF0dXMgPSAiV2lubmVyIikKaW52YXNpb25fbG9zZXIuYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShpbnZhc2lvbl9kYy5sczIsIGNoYSkpLCBzdGF0dXMgPSAiTG9zZXIiKQoKIyBwYWlyCmludmFzaW9uLmFyZWEgPC0gY2JpbmQoc2VsZWN0KGludmFzaW9uX3dpbi5hcmVhLCBXaW5uZXIgPSBhcmVhKSwKICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KGludmFzaW9uX2xvc2VyLmFyZWEsIExvc2VyID0gYXJlYSkpICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBpZmVsc2UoV2lubmVyPkxvc2VyLCAiV2lubmVyIGxhcmdlciBhcmVhIiwgIkxvc2VyIGxhcmdlciBhcmVhIikpCmBgYAoKIyBwbG90CmBgYHtyfQppbnZhc2lvbl9hcmVhLnBsIDwtZ2dwYWlyZWQoaW52YXNpb24uYXJlYSwgY29uZDEgPSAiV2lubmVyIiwgY29uZDIgPSAiTG9zZXIiLCBsaW5lLmNvbG9yID0gImNsYXNzaWZpY2F0aW9uIiwgYWxwaGEgPSAwLjIpICsKICBsYWJzKHggPSAiU3RhdHVzIiwgeSA9ICJBcmVhIiwgY29sb3IgPSAiQ29tcGFyaXNvbiIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiTG9zZXIgbGFyZ2VyIGFyZWEiID0gIiNmYzhkNTkiLCAiV2lubmVyIGxhcmdlciBhcmVhIiA9ICIjNDU3NWI0IikpICsKICBzdGF0X2NvbXBhcmVfbWVhbnMocGFpcmVkID0gVFJVRSwgaGp1c3QgPSAtMC4zKQpgYGAKCiMtLS0tLS0gcGxvdCB0b2dldGhlciAtLS0tLS0tLS0tLS0tIwpgYGB7cn0Kc3RhdGljX2ludmFzaW9uX2FyZWEucGwgPC0gZ2dhcnJhbmdlKHN0YXRpY19hcmVhLnBsLCBpbnZhc2lvbl9hcmVhLnBsLCBhbGlnbiA9ICJoIiwgY29tbW9uLmxlZ2VuZCA9IFQsIGxhYmVscyA9IGMoIkciKSkKCnN0YXRpY19pbnZhc2lvbl9kYy5wbCA8LSBnZ2FycmFuZ2Uoc3RhdGljX2RjLnBsLCBpbnZhc2lvbl9kYy5wbCwgIG5jb2wgPSAyLCBhbGlnbiA9ICJoIiwgbGFiZWxzID0gYygiRSIsICJGIiksIGNvbW1vbi5sZWdlbmQgPSBUKQoKZ2dhcnJhbmdlKHN0YXRpY19pbnZhc2lvbl9kYy5wbCwgc3RhdGljX2ludmFzaW9uX2FyZWEucGwsIG5jb2wgPSAyLCBhbGlnbiA9ICJoIiwgd2lkdGhzID0gYygxLCAxLjMpKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vZGlzZWFzZV9jdXJ2ZTIudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjI1MCwgaGVpZ2h0ID0gNTUwLCBzY2FsZSA9IDIuNSwgZHBpPTMwMCwgY29tcHJlc3Npb24gPSAibHp3IikKYGBgCgoKCgoK